@autofleet/node-common 1.7.3-beta-1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,17 +1,7 @@
1
- const Network = require('./network');
2
- const Logger = require('./logger');
3
1
  const Settings = require('./settings');
4
- const client = require('./delorean-client');
5
2
  const Router = require('./router');
6
- const Queue = require('./queue');
7
3
 
8
4
  module.exports = {
9
- Network,
10
- Logger,
11
5
  Settings,
12
- Delorean: {
13
- client,
14
- },
15
6
  Router,
16
- Queue,
17
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/node-common",
3
- "version": "1.7.3-beta-1",
3
+ "version": "2.0.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "coverage": "jest --coverage --forceExit --runInBand",
@@ -23,12 +23,9 @@
23
23
  },
24
24
  "homepage": "https://github.com/Autofleet/node-common",
25
25
  "dependencies": {
26
- "@google-cloud/logging-winston": "^0.10.2",
27
- "@google-cloud/pubsub": "^0.20.1",
28
- "axios": "^0.21.1",
26
+ "axios": "^0.18.0",
29
27
  "axios-retry": "^3.1.0",
30
28
  "dotenv": "^5.0.1",
31
- "event-pubsub": "^4.3.0",
32
29
  "express": "^4.16.2",
33
30
  "jest": "^22.4.4",
34
31
  "mock-socket": "^7.1.0",
@@ -1,52 +0,0 @@
1
- const tk = require('timekeeper');
2
- const WebSocket = require('ws');
3
- const Logger = require('../logger');
4
-
5
- const logger = Logger();
6
-
7
- const createWs = (host, resolve) => {
8
- const ws = new WebSocket(`ws://${host}`);
9
-
10
- ws.on('open', () => {
11
- ws.send(JSON.stringify({ type: 'ping' }));
12
- if (resolve) {
13
- resolve(true);
14
- }
15
- });
16
-
17
- ws.on('error', (error) => {
18
- logger.error('ERROR', error);
19
- });
20
-
21
- ws.on('message', (data) => {
22
- const jsonMsg = JSON.parse(data);
23
-
24
- if (jsonMsg.type === 'freeze') {
25
- logger.info('I know you just sent me back to the future, but I\'m back.I\'m back from the future.', { goingBackTo: jsonMsg.time });
26
- tk.freeze(new Date(jsonMsg.time));
27
- } else if (jsonMsg.type === 'travel') {
28
- tk.travel(jsonMsg.time);
29
- }
30
- });
31
-
32
- ws.on('close', () => {
33
- setTimeout(() => {
34
- if (process.env.TIME_TRAVEL_MS_SERVICE_HOST === host) {
35
- createWs(host, null);
36
- }
37
- }, 500);
38
- });
39
- };
40
-
41
- module.exports = () => new Promise((resolve) => {
42
- const { TIME_TRAVEL_MS_SERVICE_HOST, SHOULD_TIME_TRAVEL } = process.env;
43
- if (TIME_TRAVEL_MS_SERVICE_HOST && SHOULD_TIME_TRAVEL) {
44
- logger.info('If my calculations are correct, when this baby hits 88 miles per hour... you\'re gonna see some serious shit.', {
45
- TIME_TRAVEL_MS_SERVICE_HOST,
46
- });
47
-
48
- createWs(TIME_TRAVEL_MS_SERVICE_HOST, resolve);
49
- } else {
50
- resolve(false);
51
- }
52
- });
@@ -1,105 +0,0 @@
1
- const tk = require('timekeeper');
2
- const deloreanClient = require('./index');
3
- const portfinder = require('portfinder');
4
- const WebSocket = require('ws');
5
-
6
- const { env } = process;
7
-
8
- const createUrl = async () => {
9
- const port = await portfinder.getPortPromise();
10
- return {
11
- url: `127.0.0.1:${port}`,
12
- port,
13
- };
14
- };
15
-
16
- const mockServer = (port, time, type) => {
17
- const wss = new WebSocket.Server({ port });
18
- let gotPing = false;
19
-
20
- wss.on('connection', (ws) => {
21
- ws.on('message', (message) => {
22
- const json = JSON.parse(message);
23
- if (json.type === 'ping') {
24
- gotPing = true;
25
- }
26
- });
27
-
28
- ws.send(JSON.stringify({
29
- type,
30
- time,
31
- }));
32
- });
33
-
34
- return {
35
- close: () => wss.close(),
36
- gotPing: () => gotPing,
37
- };
38
- };
39
-
40
- describe('Logger', () => {
41
- beforeEach(() => {
42
- tk.reset();
43
- env.SHOULD_TIME_TRAVEL = true;
44
- env.TIME_TRAVEL_MS_SERVICE_HOST = '';
45
- });
46
-
47
- afterAll(() => {
48
- env.SHOULD_TIME_TRAVEL = false;
49
- env.TIME_TRAVEL_MS_SERVICE_HOST = '0';
50
- });
51
-
52
- test('Conects to server, sends ping an freeze time', async (done) => {
53
- const { url, port } = await createUrl();
54
- env.TIME_TRAVEL_MS_SERVICE_HOST = url;
55
- const mockedDate = new Date('2013-10-08 12:32:50 +0530').getTime();
56
- const { close, gotPing } = mockServer(port, mockedDate, 'freeze');
57
- await deloreanClient();
58
-
59
- setTimeout(() => {
60
- expect(Date.now()).toEqual(mockedDate);
61
- expect(gotPing()).toBeTruthy();
62
- close();
63
- done();
64
- }, 100);
65
- });
66
-
67
- it('Conects to server, sends ping an freeze time', async (done) => {
68
- const { url, port } = await createUrl();
69
- env.TIME_TRAVEL_MS_SERVICE_HOST = url;
70
- const mockedDate = new Date('2013-10-08 12:32:50 +0530').getTime();
71
- const { close, gotPing } = mockServer(port, mockedDate, 'travel');
72
- await deloreanClient();
73
-
74
- setTimeout(() => {
75
- expect(Date.now()).toBeGreaterThan(mockedDate);
76
- expect(Date.now()).toBeLessThan(new Date('2013-10-08 13:32:50 +0530').getTime());
77
- expect(gotPing()).toBeTruthy();
78
- close();
79
- done();
80
- }, 100);
81
- });
82
-
83
- it('Wont start without TIME_TRAVEL_MS_SERVICE_HOST', async () => {
84
- const { port } = await createUrl();
85
- delete env.TIME_TRAVEL_MS_SERVICE_HOST;
86
- const mockedDate = new Date('2013-10-08 12:32:50 +0530').getTime();
87
- const { close } = mockServer(port, mockedDate, 'travel');
88
- const result = await deloreanClient();
89
-
90
- expect(result).toBeFalsy();
91
- close();
92
- });
93
-
94
- it('Wont start without SHOULD_TIME_TRAVEL', async () => {
95
- const { url, port } = await createUrl();
96
- env.TIME_TRAVEL_MS_SERVICE_HOST = url;
97
- delete env.SHOULD_TIME_TRAVEL;
98
- const mockedDate = new Date('2013-10-08 12:32:50 +0530').getTime();
99
- const { close } = mockServer(port, mockedDate, 'travel');
100
- const result = await deloreanClient();
101
-
102
- expect(result).toBeFalsy();
103
- close();
104
- });
105
- });
package/logger/example.js DELETED
@@ -1,5 +0,0 @@
1
- const logger = require('./index')();
2
-
3
- logger.info('it is working');
4
- logger.error('errors displayed in logs/error.log', { e: new Error('test error') });
5
- logger.debug('debug with object', { a: 5 });
package/logger/index.js DELETED
@@ -1,114 +0,0 @@
1
- const winston = require('winston');
2
-
3
- const { createLogger } = winston;
4
- require('dotenv').config();
5
-
6
- const { env } = process;
7
-
8
- const infoEnvNmaes = [
9
- 'production',
10
- 'staging',
11
- 'test',
12
- ];
13
-
14
- const serializeError = (error) => {
15
- const fields = ['code', 'status', 'statusCode', 'message', 'messageData', 'name', 'stack', 'stackTrace'];
16
- return fields.reduce((v, field) => ({ ...v, [field]: error[field] }), {});
17
- };
18
-
19
- const getLevel = (logLevel) => {
20
- if (logLevel) return logLevel;
21
- if (env.LOG_LEVEL) return env.LOG_LEVEL;
22
- if (infoEnvNmaes.includes(env.NODE_ENV)) return 'info';
23
- if (env.NODE_ENV === 'development') return 'debug';
24
- return 'debug';
25
- };
26
-
27
- const enumerateErrorFormat = winston.format((info) => {
28
- if (info.message instanceof Error) {
29
- info.message = Object.assign({ // eslint-disable-line
30
- message: info.message.message,
31
- stack: info.message.stack,
32
- }, info.message);
33
- }
34
- if (info instanceof Error) {
35
- return Object.assign({
36
- message: info.message,
37
- stack: info.stack,
38
- }, info);
39
- }
40
-
41
- // eslint-disable-next-line array-callback-return
42
- Object.keys(info).map((k) => {
43
- if (info[k] instanceof Error) {
44
- // eslint-disable-next-line no-param-reassign
45
- info[k] = serializeError(info[k]);
46
- }
47
- });
48
-
49
- return info;
50
- });
51
-
52
- const getFormat = () => {
53
- if (env.NODE_ENV === 'production') {
54
- return winston.format.combine(
55
- enumerateErrorFormat(),
56
- winston.format.json(),
57
- );
58
- }
59
-
60
- return winston.format.combine(
61
- enumerateErrorFormat(),
62
- winston.format.splat(),
63
- winston.format.colorize(),
64
- winston.format.simple(),
65
- );
66
- };
67
-
68
- const createLoggerInstance = (level, exceptionHandlers) => {
69
- const transports = [new winston.transports.Console()];
70
-
71
- const logger = createLogger({
72
- level,
73
- format: getFormat(),
74
- transports,
75
- exceptionHandlers,
76
- exitOnError: false,
77
- });
78
-
79
- logger.httpMorganInfo = (options) => {
80
- logger.info(options.url, {
81
- httpRequest: {
82
- status: options.status,
83
- requestUrl: options.url,
84
- requestMethod: options.method,
85
- responseSize: options['content-length'],
86
- latency: {
87
- seconds: parseInt(options['response-time'], 10) / 1000,
88
- nanos: parseInt(options['response-time'], 10) * 1000000,
89
- },
90
- userAgent: options['user-agent'],
91
- },
92
- });
93
- };
94
- if (env.NODE_ENV !== 'production') {
95
- logger.httpMorganInfo = undefined;
96
- }
97
- return logger;
98
- };
99
-
100
- class LoggerInstanceManager {
101
- static getLoggerInstance(logLevel) {
102
- if (!LoggerInstanceManager.instances) {
103
- LoggerInstanceManager.instances = {};
104
- }
105
- const level = getLevel(logLevel);
106
- if (!LoggerInstanceManager.instances[level]) {
107
- LoggerInstanceManager.instances[level] = createLoggerInstance(level);
108
- }
109
- return LoggerInstanceManager.instances[level];
110
- }
111
- }
112
-
113
-
114
- module.exports = LoggerInstanceManager.getLoggerInstance;
@@ -1,54 +0,0 @@
1
- const Logger = require('./index');
2
-
3
- const { env } = process;
4
-
5
- describe('Logger', () => {
6
- it('it`s default level is info', () => {
7
- env.NODE_ENV = '';
8
- const logger = Logger();
9
- expect(logger).toBeDefined();
10
- expect(logger.level).toBe('debug');
11
- });
12
-
13
- it('its default develpment level is debug', () => {
14
- env.NODE_ENV = 'development';
15
- const logger = Logger();
16
- expect(logger.level).toBe('debug');
17
- });
18
-
19
- it('its default test level is info', () => {
20
- env.NODE_ENV = 'test';
21
- const logger = Logger();
22
- expect(logger.level).toBe('info');
23
- });
24
-
25
- it('its default production level is info', () => {
26
- env.NODE_ENV = 'production';
27
- const logger = Logger();
28
- expect(logger.level).toBe('info');
29
- });
30
-
31
- it('its level can be override by LOG_LEVEL env variable', () => {
32
- env.NODE_ENV = 'development';
33
- env.LOG_LEVEL = 'warn';
34
- const logger = Logger();
35
- expect(logger.level).toBe('warn');
36
- });
37
-
38
- it('its level can be override by function variable', () => {
39
- env.NODE_ENV = 'production';
40
- env.LOG_LEVEL = 'warn';
41
- const logger = Logger('silly');
42
- expect(logger.level).toBe('silly');
43
- });
44
-
45
- it('its has functions for each level', () => {
46
- const logger = Logger();
47
- expect(logger.error).toBeFunction();
48
- expect(logger.warn).toBeFunction();
49
- expect(logger.info).toBeFunction();
50
- expect(logger.verbose).toBeFunction();
51
- expect(logger.debug).toBeFunction();
52
- expect(logger.silly).toBeFunction();
53
- });
54
- });
package/network/index.js DELETED
@@ -1,105 +0,0 @@
1
- const axios = require('axios');
2
- const axiosRetry = require('axios-retry');
3
- const Logger = require('../logger');
4
- const qs = require('qs');
5
- const httpAdapter = require('axios/lib/adapters/http');
6
- require('dotenv').config();
7
- /**
8
- * Add support for nock testing
9
- * see s://github.com/axios/axios/issues/305
10
- */
11
- if (process.env.NODE_ENV === 'test') {
12
- axios.defaults.adapter = httpAdapter;
13
- }
14
-
15
- const HTTPMethods = [
16
- 'get',
17
- 'post',
18
- 'delete',
19
- 'head',
20
- 'put',
21
- 'patch',
22
- 'options',
23
- ];
24
-
25
- const defaultSettings = {
26
- timeout: 10000,
27
- headers: { 'X-AF-AUTH': 'ANYONE' },
28
- paramsSerializer: params => qs.stringify(params, { arrayFormat: 'brackets' }),
29
- };
30
-
31
- const getHttpRequestObject = response => ({
32
- status: response.status ? response.status : undefined,
33
- requestUrl: response.config ? response.config.url : undefined,
34
- query: response.config ? response.config.params : undefined,
35
- body: response.config ? response.config.data : undefined,
36
- requestMethod: response.config ? response.config.method.toUpperCase() : undefined,
37
- message: response.message ? response.message.toString() : undefined,
38
- stack: response.stack ? response.stack.toString() : undefined,
39
- });
40
-
41
- module.exports = class Network {
42
- constructor(settings = {}) {
43
- this.settings = Object.assign({}, defaultSettings, settings);
44
- this.createBaseUrl();
45
-
46
- this.axios = axios.create(this.settings);
47
- this.addRetry(settings);
48
- this.buildClassHttpMethods();
49
- this.addLogs();
50
- }
51
-
52
- addRetry(settings) {
53
- axiosRetry(this.axios, {
54
- retries: 0,
55
- retryDelay: axiosRetry.exponentialDelay,
56
- ...settings,
57
- });
58
- }
59
-
60
- addLogs() {
61
- const logger = Logger();
62
- this.axios.interceptors.request.use((request) => {
63
- logger.info(`Start Request: [${request.method.toUpperCase()}] ${request.baseURL} ${request.url}`, {
64
- headers: request.headers,
65
- query: request.params,
66
- body: request.data,
67
- });
68
- return request;
69
- });
70
-
71
- this.axios.interceptors.response.use((response) => {
72
- logger.info(`Finish Request: ${response.config.method.toUpperCase()} ${response.config.url}`, getHttpRequestObject(response));
73
- return response;
74
- }, (error) => {
75
- logger.error('Finish Request with error', { data: error.response ? error.response.data : undefined, ...getHttpRequestObject(error.response || error) });
76
- return error;
77
- });
78
- }
79
-
80
- createBaseUrl() {
81
- if (!this.settings.serviceUrl && !this.settings.serviceName) {
82
- throw new Error('At least one of the settings Missing serviceUrl or serviceName');
83
- }
84
-
85
- const { settings } = this;
86
- if (settings.serviceUrl) {
87
- settings.baseURL = settings.serviceUrl;
88
- } else if (settings.serviceName) {
89
- const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;
90
- settings.baseURL = `http://${process.env[envServiceHostName]}`;
91
- if (!settings.baseURL) {
92
- throw new Error(`Missing environment variable: ${envServiceHostName}`);
93
- }
94
- }
95
- }
96
-
97
- /**
98
- * Build class methods that wrap axios methods
99
- */
100
- buildClassHttpMethods() {
101
- HTTPMethods.forEach((method) => {
102
- this[method] = (...args) => this.axios[method](...args);
103
- });
104
- }
105
- };
@@ -1,69 +0,0 @@
1
- const nock = require('nock');
2
- const Network = require('./index');
3
-
4
- nock('http://www.google.com')
5
- .get('/resource')
6
- .reply(200, { one: 1 });
7
-
8
-
9
- nock('https://www.apple.com')
10
- .get('/resource')
11
- .reply(200, { two: 2 });
12
-
13
- describe('Network', () => {
14
- it('Making requests by service name from ENV', async () => {
15
- process.env.TEST_SERVICE_HOST = 'www.google.com';
16
- const n = new Network({ serviceName: 'TEST' });
17
- const response = await n.get('/resource');
18
- expect(response).toBeDefined();
19
- expect(response.data).toBeDefined();
20
- expect(response.data.one).toBe(1);
21
- });
22
-
23
- it('Making requests by service name from url', async () => {
24
- const n = new Network({ serviceUrl: 'https://www.apple.com' });
25
- const response = await n.get('/resource');
26
- expect(response).toBeDefined();
27
- expect(response.data).toBeDefined();
28
- expect(response.data.two).toBe(2);
29
- });
30
-
31
- // it('Getting 404', async () => {
32
- // const n = new Network({ serviceUrl: 'https://github.com/' });
33
-
34
- // const action = async () => n.get('/404', {
35
- // query: {
36
- // a: 'b',
37
- // },
38
- // });
39
-
40
- // expect(action()).rejects.toThrow(Error);
41
- // });
42
-
43
- test('Retry 1 time', async () => {
44
- nock('https://www.apple2.com')
45
- .get('/resource')
46
- .once()
47
- .reply(500);
48
-
49
-
50
- nock('https://www.apple2.com')
51
- .get('/resource')
52
- .once()
53
- .reply(200, { two: 2 });
54
-
55
- const n = new Network({ serviceUrl: 'https://www.apple2.com' });
56
- const response = await n.get('/resource', {
57
- query: {
58
- a: 'b',
59
- },
60
- 'axios-retry': {
61
- retries: 1,
62
- },
63
- });
64
-
65
- expect(response).toBeDefined();
66
- expect(response.data).toBeDefined();
67
- expect(response.data.two).toBe(2);
68
- });
69
- });
package/queue/index.js DELETED
@@ -1,107 +0,0 @@
1
- const NodeResque = require('node-resque');
2
- const logger = require('../logger')();
3
-
4
- const redisBaseSettings = {
5
- pkg: 'ioredis',
6
- host: '127.0.0.1',
7
- password: '',
8
- port: 6379,
9
- database: 0,
10
- namespace: 'resque',
11
- };
12
-
13
- class AfQueue {
14
- static redisParams(params) {
15
- return Object.assign({}, redisBaseSettings, params);
16
- }
17
-
18
- constructor() {
19
- this.inited = false;
20
- }
21
-
22
- async exitHandler() {
23
- process.stdin.resume();
24
-
25
- if (this.existing) {
26
- return;
27
- }
28
-
29
- this.existing = true;
30
- logger.info('Will remove AfQueue');
31
-
32
- if (this.worker) {
33
- await this.worker.end();
34
- }
35
-
36
- if (this.queue) {
37
- await this.queue.end();
38
- }
39
-
40
- if (this.scheduler) {
41
- await this.scheduler.end();
42
- }
43
-
44
- process.exit();
45
- }
46
-
47
- async init(connectionDetails, workerSettings, shouldCreateQueue = true) {
48
- if (this.inited) {
49
- throw new Error('AfQueue: Already inited');
50
- }
51
-
52
- const redisConf = Object.assign({}, redisBaseSettings, connectionDetails);
53
- this.inited = true;
54
- const promiseArr = [];
55
- if (shouldCreateQueue) {
56
- await this.startQueue(redisConf);
57
- promiseArr.push(this.startScheduler(redisConf));
58
- }
59
-
60
- if (workerSettings) {
61
- promiseArr.push(this.startWorker(redisConf, workerSettings));
62
- }
63
-
64
- process.on('SIGINT', this.exitHandler.bind(this));
65
- process.on('SIGTERM', this.exitHandler.bind(this));
66
-
67
- return Promise.all(promiseArr);
68
- }
69
-
70
- async getQueue() {
71
- if (!this.queue) {
72
- await this.startQueue();
73
- }
74
- return this.queue;
75
- }
76
-
77
- async startScheduler(connectionDetails) {
78
- this.scheduler = new NodeResque.Scheduler({
79
- connection: AfQueue.redisParams(connectionDetails),
80
- });
81
- await this.scheduler.connect();
82
- this.scheduler.start();
83
- }
84
-
85
- async startQueue(connectionDetails) {
86
- this.queue = new NodeResque.Queue({
87
- connection: AfQueue.redisParams(connectionDetails),
88
- });
89
- await this.queue.connect();
90
- }
91
-
92
- async startWorker(connectionDetails, { queues, jobs }) {
93
- this.worker = new NodeResque.MultiWorker({
94
- connection: AfQueue.redisParams(connectionDetails),
95
- queues,
96
- minTaskProcessors: 1,
97
- maxTaskProcessors: 10,
98
- checkTimeout: 5000,
99
- maxEventLoopDelay: 10,
100
- }, jobs);
101
-
102
- await this.worker.start();
103
- }
104
- }
105
-
106
-
107
- module.exports = new AfQueue();