Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
5.6 KiB

  1. /**
  2. * File: Includes.js
  3. *
  4. * Module used for fetching static content for the website
  5. * like js, css, images, and other static html pages
  6. *
  7. * @author Jeffery Russell
  8. */
  9. const HEADER_KEY = "header";
  10. const FOOTER_KEY = "footer";
  11. //name of header file
  12. const HEADER_FILE = "includes/html/header.html";
  13. //path of footer file
  14. const FOOTER_FILE = "includes/html/footer.html";
  15. //admin header path
  16. const ADMIN_HEADER = "includes/html/adminHeader.html";
  17. //used for hashing stuff for the header's e-tag for clients cache
  18. const crypto = require('crypto');
  19. //caching program to make the application run faster
  20. const cache = require('memory-cache');
  21. const fs = require('fs');
  22. const readFile = function(filename)
  23. {
  24. return new Promise(function(resolve, reject)
  25. {
  26. try
  27. {
  28. resolve(fs.readFileSync(filename));
  29. }
  30. catch (e)
  31. {
  32. console.log(e);
  33. console.log("Could not find " + filename);
  34. return("");
  35. }
  36. })
  37. };
  38. /**
  39. * Sends a static file to the client in a way which the web browser
  40. * caches the contents sent.
  41. *
  42. * @param cache -- server's hashmap which reduces file io
  43. * @param path -- file requested by user
  44. * @param type -- type of file for the header
  45. * @param result -- sent to client
  46. */
  47. const sendCachedContent = function(path, type, result)
  48. {
  49. const goods = cache.get(path);
  50. if(goods == null)
  51. {
  52. readFile(path).then(function(content)
  53. {
  54. const eTag = crypto.createHash('md5').update(content).digest('hex');
  55. result.writeHead(200, {'Content-Type': type, 'Cache-Control':
  56. 'public, max-age=2678400', 'ETag': '"' + eTag + '"',
  57. 'Vary': 'Accept-Encoding'});
  58. result.write(content);
  59. result.end();
  60. }).catch(function(error)
  61. {
  62. cache.del(path);
  63. console.log(error);
  64. });
  65. }
  66. else
  67. {
  68. const eTag = crypto.createHash('md5').update(goods).digest('hex');
  69. result.writeHead(200, {'Content-Type': type,
  70. 'Cache-Control': 'public, max-age=2678400',
  71. 'ETag': '"' + eTag + '"',
  72. 'Vary': 'Accept-Encoding'});
  73. result.write(goods);
  74. result.end();
  75. }
  76. };
  77. module.exports =
  78. {
  79. /** Appends the header html section to the result which is
  80. * sent to the user.
  81. *
  82. * @param result
  83. * @return {*} a promise retrieved from the utils.include function
  84. */
  85. printHeader: function(templateContext)
  86. {
  87. return module.exports.includeInObject(HEADER_KEY, templateContext, HEADER_FILE);
  88. },
  89. includeInObject: function(key, context, fileName)
  90. {
  91. return new Promise(function(resolve, reject)
  92. {
  93. readFile(fileName).then(function(result)
  94. {
  95. context[key] = result;
  96. resolve();
  97. }).catch(function(error)
  98. {
  99. context[key] = "File Not Found";
  100. reject(error);
  101. console.log(error);
  102. })
  103. });
  104. },
  105. /**
  106. * A function similar to the include statement in PHP
  107. * This function writes a file to the output
  108. *
  109. * @param fileName the file to append to the result
  110. */
  111. include: function(fileName)
  112. {
  113. return readFile(fileName);
  114. },
  115. /**
  116. * Appends the footer to the result object
  117. *
  118. * @return {*|Promise}
  119. */
  120. printFooter: function(templateContext)
  121. {
  122. return module.exports.includeInObject(FOOTER_KEY, templateContext, FOOTER_FILE);
  123. },
  124. /**
  125. * Displays the admin header
  126. *
  127. * @returns {*|Promise}
  128. */
  129. printAdminHeader(templateContext)
  130. {
  131. return module.exports.includeInObject(HEADER_KEY, templateContext, ADMIN_HEADER);
  132. },
  133. /**Sends a css file to the user
  134. *
  135. * @param result
  136. * @param path
  137. * @return {*}
  138. */
  139. sendCSS: function(result, path)
  140. {
  141. sendCachedContent(path, 'text/css', result);
  142. },
  143. /**Sends the user an image from the specified fileName.
  144. *
  145. * @param result
  146. * @param fileName
  147. */
  148. sendImage: function(result, fileName)
  149. {
  150. sendCachedContent(fileName, 'image/png', result);
  151. },
  152. /**Sends the user an image from the specified fileName.
  153. *
  154. * @param result
  155. * @param fileName
  156. */
  157. sendJS: function(result, fileName)
  158. {
  159. sendCachedContent(fileName, 'application/javascript', result);
  160. },
  161. /** Might want to change this to be non cached later
  162. *
  163. * @param result
  164. * @param fileName
  165. */
  166. sendPDF: function(result, fileName)
  167. {
  168. sendCachedContent(fileName, 'application/pdf', result);
  169. },
  170. fetchTemplate: function(templateName)
  171. {
  172. return readFile("templates/" + templateName);
  173. },
  174. /**Sends the user an image from the specified fileName.
  175. *
  176. * @param result
  177. * @param fileName
  178. */
  179. sendHTML: function(result, fileName)
  180. {
  181. readFile(fileName).then(function(content)
  182. {
  183. result.writeHead(200, {'Content-Type': 'text/html'});
  184. result.write(content);
  185. result.end();
  186. }).catch(function(error)
  187. {
  188. console.log(error);
  189. });
  190. },
  191. /**
  192. * Sends a svg file to the client.
  193. *
  194. * @param result
  195. * @param fileName
  196. */
  197. sendSVG: function(result, fileName)
  198. {
  199. sendCachedContent(fileName, 'image/svg+xml', result);
  200. },
  201. /**
  202. * Clears the cache
  203. */
  204. clearCache: function()
  205. {
  206. console.log("Includes cache cleared");
  207. cache.clear();
  208. }
  209. };