Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

151 righe
5.4 KiB

  1. const config = require('../setup/config');
  2. const debug = require('debug')('server-connect:router');
  3. const { clone } = require('./util');
  4. const App = require('./app');
  5. module.exports = {
  6. cache: function(options) {
  7. return async function(req, res, next) {
  8. if (!options.ttl || !global.redisClient) {
  9. // no caching
  10. return next();
  11. }
  12. let key = 'erc:' + (req.originalUrl || req.url);
  13. let nocache = false;
  14. let nostore = false;
  15. if (req.fragment) {
  16. key += '-fragment';
  17. }
  18. if (req.query.nocache) {
  19. nocache = true;
  20. }
  21. try {
  22. const cacheControl = req.get('Cache-Control');
  23. if (cacheControl) {
  24. if (cacheControl.includes('no-cache')) nocache = true;
  25. if (cacheControl.includes('no-store')) nostore = true;
  26. }
  27. } catch (err) {
  28. // Ignore but log errors
  29. console.error(err);
  30. }
  31. if (!nocache) {
  32. try {
  33. const cache = await global.redisClient.hGetAll(key);
  34. if (cache.body) {
  35. res.type(cache.type || 'text/html');
  36. res.send(cache.body);
  37. return;
  38. }
  39. } catch (err) {
  40. // Ignore but log errors
  41. console.error(err);
  42. }
  43. }
  44. if (!nostore) {
  45. // wrap res.send
  46. const send = res.send.bind(res);
  47. res.send = function (body) {
  48. const ret = send(body);
  49. if (this.statusCode !== 200 || typeof body !== 'string') {
  50. // do not cache when not status 200 or body is not a string
  51. return ret;
  52. }
  53. global.redisClient.hSet(key, {
  54. body: body,
  55. type: this.get('Content-Type') || 'text/html'
  56. }).then(() => {
  57. return global.redisClient.expire(key, +options.ttl);
  58. }).catch(err => {
  59. // Ignore but log errors
  60. console.error(err);
  61. });
  62. return ret;
  63. };
  64. }
  65. return next();
  66. };
  67. },
  68. serverConnect: function(json) {
  69. return async function(req, res, next) {
  70. const app = new App(req, res);
  71. debug(`Serving serverConnect ${req.path}`);
  72. return Promise.resolve(app.define(json)).catch(next);
  73. };
  74. },
  75. templateView: function(layout, page, data, exec) {
  76. return async function(req, res, next) {
  77. const app = new App(req, res);
  78. debug(`Serving templateView ${req.path}`);
  79. const routeData = clone(data);
  80. const methods = {
  81. _: (expr, data = {}) => {
  82. return app.parse(`{{${expr}}}`, app.scope.create(data));
  83. },
  84. _exec: async (name, steps, data = {}) => {
  85. let context = {};
  86. app.scope = app.scope.create(data, context);
  87. await app.exec(steps, true);
  88. app.scope = app.scope.parent;
  89. app.set(name, context);
  90. return context;
  91. },
  92. _repeat: (expr, cb) => {
  93. let data = app.parse(`{{${expr}}}`);
  94. if (Array.isArray(data)) return data.forEach(cb);
  95. return '';
  96. },
  97. _route: req.route.path
  98. };
  99. let template = page;
  100. if (layout && !req.fragment) {
  101. routeData.content = '/' + page;
  102. template = 'layouts/' + layout;
  103. }
  104. if (exec) {
  105. return Promise.resolve(app.define(exec, true)).then(() => {
  106. if (!res.headersSent) {
  107. app.set(app.parse(routeData));
  108. debug(`Render template ${template}`);
  109. debug(`Template data: %O`, Object.assign({}, app.global.data, app.data));
  110. res.render(template, Object.assign({}, app.global.data, app.data, methods), async (err, html) => {
  111. // callback is needed when using ejs with aync, html is a promise
  112. if (err) return next(err);
  113. html.then(html => res.send(html)).catch(err => next(err));
  114. });
  115. }
  116. }).catch(next)
  117. } else {
  118. app.set(app.parse(routeData));
  119. debug(`Render template ${template}`);
  120. debug(`Template data: %O`, app.global.data);
  121. res.render(template, Object.assign({}, app.global.data, methods), async (err, html) => {
  122. // callback is needed when using ejs with aync, html is a promise
  123. if (err) return next(err);
  124. html.then(html => res.send(html)).catch(err => next(err));
  125. });
  126. }
  127. };
  128. }
  129. };