From 04461d13f1886838f18930e97f9870827dc6c0b8 Mon Sep 17 00:00:00 2001 From: Upendra Dev Singh Date: Sun, 17 Feb 2019 22:18:15 +0530 Subject: [PATCH] UPDATE: adding custom gateway --- ironhead/app/gateway/article.js | 7 -- ironhead/app/hooks/gateway/init.js | 27 ------- ironhead/app/hooks/httpClient.js | 13 +++ ironhead/app/hooks/index.js | 6 +- ironhead/app/hooks/init.js | 13 --- ironhead/app/hooks/redis.js | 10 +++ ironhead/app/modules/story/gatewayConfig.js | 16 ++++ .../story/{routes/article.js => route.js} | 2 +- ironhead/app/routes/index.js | 2 +- ironhead/config/config.js | 2 + ironhead/config/ease-config/ease/getConfig.js | 11 --- ironhead/config/gateway.js | 3 + ironhead/config/http-client/ease/getConfig.js | 5 ++ .../header/index.js | 0 .../server/development.js | 0 .../server/production.js | 0 .../server/staging.js | 0 ironhead/lib/package/adapter/redis/index.js | 28 +++++++ ironhead/lib/package/gateway/cacheClient.js | 22 +++++ ironhead/lib/package/gateway/httpClient.js | 59 ++++++++++++++ ironhead/lib/package/gateway/index.js | 30 +++++++ ironhead/lib/package/gateway/util.js | 7 ++ ironhead/package-lock.json | 80 +++++++++++++++++++ ironhead/package.json | 1 + .../public/src/components/header/index.js | 6 +- .../public/src/pages/article/ArticleTmpl.js | 4 +- ironhead/public/src/styles/_typography.scss | 2 +- 27 files changed, 289 insertions(+), 67 deletions(-) delete mode 100644 ironhead/app/gateway/article.js delete mode 100644 ironhead/app/hooks/gateway/init.js create mode 100644 ironhead/app/hooks/httpClient.js delete mode 100644 ironhead/app/hooks/init.js create mode 100644 ironhead/app/hooks/redis.js create mode 100644 ironhead/app/modules/story/gatewayConfig.js rename ironhead/app/modules/story/{routes/article.js => route.js} (76%) delete mode 100644 ironhead/config/ease-config/ease/getConfig.js create mode 100644 ironhead/config/gateway.js create mode 100644 ironhead/config/http-client/ease/getConfig.js rename ironhead/config/{ease-config => http-client}/header/index.js (100%) rename ironhead/config/{ease-config => http-client}/server/development.js (100%) rename ironhead/config/{ease-config => http-client}/server/production.js (100%) rename ironhead/config/{ease-config => http-client}/server/staging.js (100%) create mode 100644 ironhead/lib/package/adapter/redis/index.js create mode 100644 ironhead/lib/package/gateway/cacheClient.js create mode 100644 ironhead/lib/package/gateway/httpClient.js create mode 100644 ironhead/lib/package/gateway/index.js create mode 100644 ironhead/lib/package/gateway/util.js diff --git a/ironhead/app/gateway/article.js b/ironhead/app/gateway/article.js deleted file mode 100644 index f2bcbd8..0000000 --- a/ironhead/app/gateway/article.js +++ /dev/null @@ -1,7 +0,0 @@ - - -module.exports = function () { - return { - configKeys: ['article'] - } -} diff --git a/ironhead/app/hooks/gateway/init.js b/ironhead/app/hooks/gateway/init.js deleted file mode 100644 index 421a9f4..0000000 --- a/ironhead/app/hooks/gateway/init.js +++ /dev/null @@ -1,27 +0,0 @@ -const { fixtures, get } = require('../../../lib/package/ease/orchestrator'); -/** - * - * @description **init** is the wrapper over ease for initiating the fixtures - * path. - *
- * - * In order to send request using ease , we need to initialize - * the config path, which ease keeps it in memory. - *
- * - * Application using knucklehead , needs to initialize it in the beginning - * since fixturing is asynchronous. - * - * @param { fixturesPath } fixturesPath - absolute config path needs to be provided. - * It's not a mandatory field otherwise it will bootstrap using the default EASE_CONFIG_PATH - *
- * @returns { Promise } Promise - ConfigPath promise is returned - */ -const init = (fixturesPath) => { - if (!fixturesPath) throw new Error('Fixtures Path for Gateway initalization not passed.'); - const configPath = fixturesPath; - global.easeDispatch = get; - return fixtures(configPath); -}; - -module.exports = init; diff --git a/ironhead/app/hooks/httpClient.js b/ironhead/app/hooks/httpClient.js new file mode 100644 index 0000000..02b8526 --- /dev/null +++ b/ironhead/app/hooks/httpClient.js @@ -0,0 +1,13 @@ +const path = require('path'); +const httpClient = require('../../lib/package/gateway/httpClient'); + +const CONFIG_PATH = path.join(__dirname, '../../config/http-client'); + +module.exports = async (app, cb) => { + try { + await httpClient.init(CONFIG_PATH); + cb(); + } catch (e) { + cb(e); + } +}; diff --git a/ironhead/app/hooks/index.js b/ironhead/app/hooks/index.js index e187035..5357be5 100644 --- a/ironhead/app/hooks/index.js +++ b/ironhead/app/hooks/index.js @@ -1,7 +1,9 @@ -const init = require('./init'); +const httpClient = require('./httpClient'); +const redis = require('./redis'); const hooks = [ - init + redis, + httpClient ]; module.exports = hooks; diff --git a/ironhead/app/hooks/init.js b/ironhead/app/hooks/init.js deleted file mode 100644 index b32c723..0000000 --- a/ironhead/app/hooks/init.js +++ /dev/null @@ -1,13 +0,0 @@ -const path = require('path'); -const gateway = require('./gateway/init'); - -const CONFIG_PATH = path.join(__dirname, '../../config/ease-config'); - -module.exports = async (app, cb) => { - try { - await gateway(CONFIG_PATH); - cb(); - } catch (e) { - cb(e); - } -}; diff --git a/ironhead/app/hooks/redis.js b/ironhead/app/hooks/redis.js new file mode 100644 index 0000000..331728f --- /dev/null +++ b/ironhead/app/hooks/redis.js @@ -0,0 +1,10 @@ +const { init } = require('../../lib/package/adapter/redis'); + +module.exports = async (app, cb) => { + try { + await init(); + cb(); + } catch (e) { + cb(e); + } +}; \ No newline at end of file diff --git a/ironhead/app/modules/story/gatewayConfig.js b/ironhead/app/modules/story/gatewayConfig.js new file mode 100644 index 0000000..eb82752 --- /dev/null +++ b/ironhead/app/modules/story/gatewayConfig.js @@ -0,0 +1,16 @@ +exports.article = { + options: { + server: 'api', + method: 'get', + endPoint: '/v2/everything?domains=wsj.com,nytimes.com' + } +}; + +exports.gateway = () => ( + { + ttl: 60, + type: 'rest', + cache: true, + configKeys: ['article'] + } +); \ No newline at end of file diff --git a/ironhead/app/modules/story/routes/article.js b/ironhead/app/modules/story/route.js similarity index 76% rename from ironhead/app/modules/story/routes/article.js rename to ironhead/app/modules/story/route.js index d3366f2..3f214a0 100644 --- a/ironhead/app/modules/story/routes/article.js +++ b/ironhead/app/modules/story/route.js @@ -1,4 +1,4 @@ -const gateway = require('../../../gateway/article'); +const { gateway } = require('./gatewayConfig'); module.exports = { domain: 'article', diff --git a/ironhead/app/routes/index.js b/ironhead/app/routes/index.js index f0c21d0..10be513 100644 --- a/ironhead/app/routes/index.js +++ b/ironhead/app/routes/index.js @@ -1,4 +1,4 @@ -const article = require('../modules/story/routes/article'); +const article = require('../modules/story/route'); const routes = [ article diff --git a/ironhead/config/config.js b/ironhead/config/config.js index e268fe7..291fcbd 100644 --- a/ironhead/config/config.js +++ b/ironhead/config/config.js @@ -1,7 +1,9 @@ const session = require('./session'); const static = require('./static'); +const gateway = require('./gateway'); module.exports = { static, + gateway, ...session }; diff --git a/ironhead/config/ease-config/ease/getConfig.js b/ironhead/config/ease-config/ease/getConfig.js deleted file mode 100644 index 8292cbf..0000000 --- a/ironhead/config/ease-config/ease/getConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -const article = { - options: { - server: 'api', - method: 'get', - endPoint: '/v2/everything?domains=wsj.com,nytimes.com' - } -} - -module.exports = { - article -}; diff --git a/ironhead/config/gateway.js b/ironhead/config/gateway.js new file mode 100644 index 0000000..d343624 --- /dev/null +++ b/ironhead/config/gateway.js @@ -0,0 +1,3 @@ +const gateway = require('../lib/package/gateway'); + +module.exports = gateway; \ No newline at end of file diff --git a/ironhead/config/http-client/ease/getConfig.js b/ironhead/config/http-client/ease/getConfig.js new file mode 100644 index 0000000..80c1419 --- /dev/null +++ b/ironhead/config/http-client/ease/getConfig.js @@ -0,0 +1,5 @@ +const { article } = require('../../../app/modules/story/gatewayConfig'); + +module.exports = { + article +}; diff --git a/ironhead/config/ease-config/header/index.js b/ironhead/config/http-client/header/index.js similarity index 100% rename from ironhead/config/ease-config/header/index.js rename to ironhead/config/http-client/header/index.js diff --git a/ironhead/config/ease-config/server/development.js b/ironhead/config/http-client/server/development.js similarity index 100% rename from ironhead/config/ease-config/server/development.js rename to ironhead/config/http-client/server/development.js diff --git a/ironhead/config/ease-config/server/production.js b/ironhead/config/http-client/server/production.js similarity index 100% rename from ironhead/config/ease-config/server/production.js rename to ironhead/config/http-client/server/production.js diff --git a/ironhead/config/ease-config/server/staging.js b/ironhead/config/http-client/server/staging.js similarity index 100% rename from ironhead/config/ease-config/server/staging.js rename to ironhead/config/http-client/server/staging.js diff --git a/ironhead/lib/package/adapter/redis/index.js b/ironhead/lib/package/adapter/redis/index.js new file mode 100644 index 0000000..627dfc9 --- /dev/null +++ b/ironhead/lib/package/adapter/redis/index.js @@ -0,0 +1,28 @@ +const Redis = require('ioredis'); +Redis.Promise = require('bluebird') + +let connection; + +module.exports = { + init() { + if (connection) { + return Promise.resolve(connection); + } + return new Promise((resolve, reject) => { + connection = new Redis(); + connection.set('testRedisConnection', 'test data'); + connection.get('testRedisConnection', function (err, data) { + if (err) { + reject(err); + } else { + if (data === 'test data') { + resolve(connection); + } + } + }); + }); + }, + getConnection() { + return connection; + } +}; diff --git a/ironhead/lib/package/gateway/cacheClient.js b/ironhead/lib/package/gateway/cacheClient.js new file mode 100644 index 0000000..55acb79 --- /dev/null +++ b/ironhead/lib/package/gateway/cacheClient.js @@ -0,0 +1,22 @@ +const { generateKey } = require('./util'); +const { getConnection } = require('../adapter/redis'); + +const get = async (config) => { + const key = generateKey(JSON.stringify(config)); + const redis = getConnection(); + const data = await redis.get(key); + + return data; +}; + +const set = (config, response) => { + const { ttl } = config; + const key = generateKey(JSON.stringify(config)); + const redis = getConnection(); + return setTimeout(() => redis.set(key, JSON.stringify(response), 'ex', ttl), 0); +}; + +module.exports = { + get, + set +}; diff --git a/ironhead/lib/package/gateway/httpClient.js b/ironhead/lib/package/gateway/httpClient.js new file mode 100644 index 0000000..e75ecf1 --- /dev/null +++ b/ironhead/lib/package/gateway/httpClient.js @@ -0,0 +1,59 @@ +const { fixtures, get } = require('../ease/orchestrator'); +/** + * + * @description **init** is the wrapper over ease for initiating the fixtures + * path. + *
+ * + * In order to send request using ease , we need to initialize + * the config path, which ease keeps it in memory. + *
+ * + * Application using knucklehead , needs to initialize it in the beginning + * since fixturing is asynchronous. + * + * @param { fixturesPath } fixturesPath - absolute config path needs to be provided. + * It's not a mandatory field otherwise it will bootstrap using the default EASE_CONFIG_PATH + *
+ * @returns { Promise } Promise - ConfigPath promise is returned + */ +const init = (fixturesPath) => { + if (!fixturesPath) throw new Error('Fixtures Path for Gateway initialization not passed.'); + const configPath = fixturesPath; + return fixtures(configPath); +}; + +const sanitize = (configKeys, response) => { + const isMulti = configKeys.length > 1; + + if (isMulti) { + const parsedResponse = configKeys.reduce((acc, key) => { + const { [key]: { statusCode, body } } = response; + acc[key] = { + ...body, + apiStatusCode: statusCode + }; + return acc; + }, {}); + + return parsedResponse; + } + const [singleKeyName] = configKeys; + const { [singleKeyName]: { statusCode, body } } = response; + return { + ...body, + apiStatusCode: statusCode + }; +}; + +const request = async ({ configKeys, reqConfig, handlers }) => { + const httpResponse = await get(configKeys, reqConfig); + const parsedResponse = sanitize(configKeys, httpResponse); + const standardResponse = typeof handler === 'function' ? handler(parsedResponse) : parsedResponse; + return standardResponse; +} + +module.exports = { + init, + request +}; diff --git a/ironhead/lib/package/gateway/index.js b/ironhead/lib/package/gateway/index.js new file mode 100644 index 0000000..36097d6 --- /dev/null +++ b/ironhead/lib/package/gateway/index.js @@ -0,0 +1,30 @@ +const httpClient = require('./httpClient'); +const cacheClient = require('./cacheClient'); + +module.exports = async (props) => { + const { reqConfig, ...gwConfig } = props; + const { configKeys, cache } = gwConfig; + + try { + if (cache) { + const data = await cacheClient.get(gwConfig); + + if (data) { + console.log('hit'); + const response = JSON.parse(data); + return response; + } + console.log('miss'); + const response = await httpClient.request(props); + cacheClient.set(gwConfig, response); + return response; + } else { + const response = await httpClient.request(props); + return response; + } + + } catch (e) { + throw e; + } +}; + diff --git a/ironhead/lib/package/gateway/util.js b/ironhead/lib/package/gateway/util.js new file mode 100644 index 0000000..1c38c0d --- /dev/null +++ b/ironhead/lib/package/gateway/util.js @@ -0,0 +1,7 @@ +const crypto = require('crypto'); + +exports.generateKey = (text) => { + const hash = crypto.createHash('md5'); + hash.update(text); + return hash.digest('hex'); +}; diff --git a/ironhead/package-lock.json b/ironhead/package-lock.json index 1acfbc1..4ec03ed 100644 --- a/ironhead/package-lock.json +++ b/ironhead/package-lock.json @@ -2973,6 +2973,11 @@ } } }, + "cluster-key-slot": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz", + "integrity": "sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4026,6 +4031,11 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, + "denque": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.0.tgz", + "integrity": "sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -5354,6 +5364,11 @@ "write": "0.2.1" } }, + "flexbuffer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flexbuffer/-/flexbuffer-0.0.6.tgz", + "integrity": "sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=" + }, "flush-write-stream": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", @@ -6622,6 +6637,38 @@ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "ioredis": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.6.2.tgz", + "integrity": "sha512-zlc/LeoeriHTXm5z3rakPcfRcUV9x+xr0E+7/L7KH0D5z7sI5ngEQWR2RUxnwFcxUcCkvrXMztRIdBP3DhqMAQ==", + "requires": { + "cluster-key-slot": "1.0.12", + "debug": "3.2.6", + "denque": "1.4.0", + "flexbuffer": "0.0.6", + "lodash.defaults": "4.2.0", + "lodash.flatten": "4.4.0", + "redis-commands": "1.4.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "1.0.2" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "ip-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-3.0.0.tgz", @@ -8179,6 +8226,16 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -11917,6 +11974,24 @@ } } }, + "redis-commands": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", + "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "1.2.0" + } + }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -13148,6 +13223,11 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==" }, + "standard-as-callback": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-1.0.2.tgz", + "integrity": "sha512-1Qrah+2Vmj8DiftcXR9gfUe/gFmOukdnxF5v7G/apCZbLtjh3rjss8Eu6Qlprm6zerrl+qDmvm7KXpJedqpoAQ==" + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", diff --git a/ironhead/package.json b/ironhead/package.json index 90297b3..17f4d7a 100644 --- a/ironhead/package.json +++ b/ironhead/package.json @@ -15,6 +15,7 @@ "body-parser": "^1.18.3", "cookie-parser": "^1.4.3", "css-loader": "^1.0.1", + "ioredis": "^4.6.2", "preact": "^8.4.2", "preact-render-to-string": "^4.1.0", "preact-router": "^2.6.1", diff --git a/ironhead/public/src/components/header/index.js b/ironhead/public/src/components/header/index.js index 0958451..90bdb85 100644 --- a/ironhead/public/src/components/header/index.js +++ b/ironhead/public/src/components/header/index.js @@ -1,10 +1,12 @@ import { h } from 'preact'; import './header.scss'; -const HeaderLayout = (props) => ( +const HeaderLayout = props => (
-

Top headlines

+
); diff --git a/ironhead/public/src/pages/article/ArticleTmpl.js b/ironhead/public/src/pages/article/ArticleTmpl.js index 4a97257..94f9f40 100644 --- a/ironhead/public/src/pages/article/ArticleTmpl.js +++ b/ironhead/public/src/pages/article/ArticleTmpl.js @@ -16,8 +16,8 @@ const ArticleTmpl = (props) => { -

{title}

-

{description}

+

+

); })} diff --git a/ironhead/public/src/styles/_typography.scss b/ironhead/public/src/styles/_typography.scss index becb91a..860aacc 100644 --- a/ironhead/public/src/styles/_typography.scss +++ b/ironhead/public/src/styles/_typography.scss @@ -22,7 +22,7 @@ a { } body { - background: #eee; + background: #fff; } h1,