|
1 | 1 | import jwt from 'jwt-simple'; |
2 | 2 | import request from 'request'; |
3 | 3 | import ProcessorFactory from '../processor/factory'; |
| 4 | +import cache from '../lib/cache-instance' |
| 5 | +import { sha3_224 } from 'js-sha3' |
| 6 | + |
| 7 | +function _cacheStorageHandler (config, result, hash, tags) { |
| 8 | + if (config.server.useOutputCache && cache) { |
| 9 | + cache.set( |
| 10 | + 'api:' + hash, |
| 11 | + result, |
| 12 | + tags |
| 13 | + ).catch((err) => { |
| 14 | + console.error(err) |
| 15 | + }) |
| 16 | + } |
| 17 | +} |
4 | 18 |
|
5 | 19 | function _updateQueryStringParameter (uri, key, value) { |
6 | 20 | var re = new RegExp('([?&])' + key + '=.*?(&|#|$)', 'i'); |
@@ -87,37 +101,71 @@ export default ({config, db}) => function (req, res, body) { |
87 | 101 | pass: config.elasticsearch.password |
88 | 102 | }; |
89 | 103 | } |
| 104 | + const s = Date.now() |
| 105 | + const reqHash = sha3_224(JSON.stringify(requestBody)) |
| 106 | + const dynamicRequestHandler = () => { |
| 107 | + request({ // do the elasticsearch request |
| 108 | + uri: url, |
| 109 | + method: req.method, |
| 110 | + body: requestBody, |
| 111 | + json: true, |
| 112 | + auth: auth |
| 113 | + }, (_err, _res, _resBody) => { // TODO: add caching layer to speed up SSR? How to invalidate products (checksum on the response BEFORE processing it) |
| 114 | + if (_resBody && _resBody.hits && _resBody.hits.hits) { // we're signing up all objects returned to the client to be able to validate them when (for example order) |
| 115 | + const factory = new ProcessorFactory(config) |
| 116 | + const tagsArray = [] |
| 117 | + if (config.server.useOutputCache && cache) { |
| 118 | + const tagPrefix = entityType[0].toUpperCase() // first letter of entity name: P, T, A ... |
| 119 | + tagsArray.push(entityType) |
| 120 | + _resBody.hits.hits.map(item => { |
| 121 | + if (item._source.id) { // has common identifier |
| 122 | + tagsArray.push(`${tagPrefix}${item._source.id}`) |
| 123 | + } |
| 124 | + }) |
| 125 | + } |
| 126 | + |
| 127 | + let resultProcessor = factory.getAdapter(entityType, indexName, req, res) |
| 128 | + |
| 129 | + if (!resultProcessor) { resultProcessor = factory.getAdapter('default', indexName, req, res) } // get the default processor |
| 130 | + |
| 131 | + if (entityType === 'product') { |
| 132 | + resultProcessor.process(_resBody.hits.hits, groupId).then((result) => { |
| 133 | + _resBody.hits.hits = result |
| 134 | + _cacheStorageHandler(config, _resBody, reqHash, tagsArray) |
| 135 | + res.json(_resBody); |
| 136 | + }).catch((err) => { |
| 137 | + console.error(err) |
| 138 | + }) |
| 139 | + } else { |
| 140 | + resultProcessor.process(_resBody.hits.hits).then((result) => { |
| 141 | + _resBody.hits.hits = result |
| 142 | + _cacheStorageHandler(config, _resBody, reqHash, tagsArray) |
| 143 | + res.json(_resBody); |
| 144 | + }).catch((err) => { |
| 145 | + console.error(err) |
| 146 | + }) |
| 147 | + } |
| 148 | + } else { // no cache storage if no results from Elastic |
| 149 | + res.json(_resBody); |
| 150 | + } |
| 151 | + }); |
| 152 | + } |
90 | 153 |
|
91 | | - request({ // do the elasticsearch request |
92 | | - uri: url, |
93 | | - method: req.method, |
94 | | - body: requestBody, |
95 | | - json: true, |
96 | | - auth: auth |
97 | | - }, (_err, _res, _resBody) => { // TODO: add caching layer to speed up SSR? How to invalidate products (checksum on the response BEFORE processing it) |
98 | | - if (_resBody && _resBody.hits && _resBody.hits.hits) { // we're signing up all objects returned to the client to be able to validate them when (for example order) |
99 | | - const factory = new ProcessorFactory(config) |
100 | | - let resultProcessor = factory.getAdapter(entityType, indexName, req, res) |
101 | | - |
102 | | - if (!resultProcessor) { resultProcessor = factory.getAdapter('default', indexName, req, res) } // get the default processor |
103 | | - |
104 | | - if (entityType === 'product') { |
105 | | - resultProcessor.process(_resBody.hits.hits, groupId).then((result) => { |
106 | | - _resBody.hits.hits = result |
107 | | - res.json(_resBody); |
108 | | - }).catch((err) => { |
109 | | - console.error(err) |
110 | | - }) |
| 154 | + if (config.server.useOutputCache && cache) { |
| 155 | + cache.get( |
| 156 | + 'api:' + reqHash |
| 157 | + ).then(output => { |
| 158 | + if (output !== null) { |
| 159 | + res.setHeader('X-VS-Cache', 'Hit') |
| 160 | + res.json(output) |
| 161 | + console.log(`cache hit [${req.url}], cached request: ${Date.now() - s}ms`) |
111 | 162 | } else { |
112 | | - resultProcessor.process(_resBody.hits.hits).then((result) => { |
113 | | - _resBody.hits.hits = result |
114 | | - res.json(_resBody); |
115 | | - }).catch((err) => { |
116 | | - console.error(err) |
117 | | - }) |
| 163 | + res.setHeader('X-VS-Cache', 'Miss') |
| 164 | + console.log(`cache miss [${req.url}], request: ${Date.now() - s}ms`) |
| 165 | + dynamicRequestHandler() |
118 | 166 | } |
119 | | - } else { |
120 | | - res.json(_resBody); |
121 | | - } |
122 | | - }); |
| 167 | + }).catch(err => console.error(err)) |
| 168 | + } else { |
| 169 | + dynamicRequestHandler() |
| 170 | + } |
123 | 171 | } |
0 commit comments