Commit d5fe86d04fda8ae13c450c11161f0ecd9a532908
1 parent
f1928f0351
Exists in
master
ready to proof
Showing 5 changed files with 287 additions and 0 deletions Side-by-side Diff
index.js
... | ... | @@ -0,0 +1,19 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const Logger = require("./lib/logger"); | |
4 | +Logger.init(); | |
5 | +const logger = Logger.get(); | |
6 | + | |
7 | +const pull = require('./lib/pull'); | |
8 | +const partner = require("./lib/partner"); | |
9 | + | |
10 | +const config = require("./config.json"); | |
11 | + | |
12 | +let options = { | |
13 | + matrix: {}, | |
14 | + config: config, | |
15 | + partner: partner | |
16 | +} | |
17 | + | |
18 | +partner.init(options); | |
19 | +pull.init(options); |
lib/logger.js
... | ... | @@ -0,0 +1,67 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const fs = require('fs'); | |
4 | +const strftime = require('strftime'); | |
5 | +const winston = require('winston'); | |
6 | +require('winston-daily-rotate-file'); | |
7 | + | |
8 | +var loggerTimestamp = function() { | |
9 | + return strftime('%F %T', new Date()); | |
10 | +} | |
11 | + | |
12 | +var logger; | |
13 | + | |
14 | +function init(_filenamePrefix) { | |
15 | + //console.trace('Inisialisasi logger'); | |
16 | + | |
17 | + const logDirectory = 'logs'; | |
18 | + fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory); | |
19 | + | |
20 | + let filenamePrefix; | |
21 | + | |
22 | + if (_filenamePrefix) { | |
23 | + filenamePrefix = logDirectory + '/' + _filenamePrefix; | |
24 | + } | |
25 | + else { | |
26 | + filenamePrefix = logDirectory + "/log"; | |
27 | + } | |
28 | + | |
29 | + logger = new winston.Logger({ | |
30 | + transports: [ | |
31 | + new (winston.transports.Console)({ | |
32 | + timestamp: function() { | |
33 | + return strftime('%F %T', new Date()); | |
34 | + }, | |
35 | + level: 'verbose', | |
36 | + }), | |
37 | + | |
38 | + new (winston.transports.DailyRotateFile) ({ | |
39 | + name: 'log-file-txt', | |
40 | + filename: filenamePrefix, | |
41 | + timestamp: loggerTimestamp, | |
42 | + formatter: function(options) { | |
43 | + return options.timestamp() | |
44 | + +' ' + options.level.toUpperCase() | |
45 | + +' ' + (undefined !== options.message ? options.message : '') | |
46 | + + (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '' ); | |
47 | + }, | |
48 | + level: 'debug', | |
49 | + }), | |
50 | + ] | |
51 | + }); | |
52 | + | |
53 | + logger.verbose(__filename + ': initialized'); | |
54 | + return logger; | |
55 | +} | |
56 | + | |
57 | +function get() { | |
58 | + if (!logger) { | |
59 | + console.trace('Logger uninitialized, aborting process'); | |
60 | + process.exit(1); | |
61 | + } else { | |
62 | + return logger; | |
63 | + } | |
64 | +} | |
65 | + | |
66 | +exports.init = init; | |
67 | +exports.get = get; |
lib/partner.js
... | ... | @@ -0,0 +1,39 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const moment = require('moment'); | |
4 | + | |
5 | +const pull = require('./pull'); | |
6 | +const logger = require('./logger').get(); | |
7 | + | |
8 | +var config; | |
9 | +var matrix; | |
10 | + | |
11 | +function init(options) { | |
12 | + config = options.config; | |
13 | + matrix = options.matrix; | |
14 | +} | |
15 | + | |
16 | +function _buy(task) { | |
17 | + let destination = Number(task.destination); | |
18 | + if (destination % 2) { | |
19 | + let msg = 'Isi ' + task.remote_product + ' ke ' + task.destination + ' gagal karena nomor tujuan ganjil'; | |
20 | + pull.report(task.trx_id, '14', msg); | |
21 | + } else { | |
22 | + let sn = moment().format('YYYYMMDDHHmmssSSS') | |
23 | + let msg = 'Isi ' + task.remote_product + ' ke ' + task.destination + ' berhasil karena nomor tujuan genap dengan SN=' + sn; | |
24 | + pull.report(task.trx_id, '00', msg, sn); | |
25 | + } | |
26 | +} | |
27 | + | |
28 | +function buy(task) { | |
29 | + logger.verbose('Buy on partner', {task: task}); | |
30 | + setTimeout( | |
31 | + function() { | |
32 | + _buy(task); | |
33 | + }, | |
34 | + 2000 | |
35 | + ) | |
36 | +} | |
37 | + | |
38 | +exports.init = init; | |
39 | +exports.buy = buy; |
lib/pull.js
... | ... | @@ -0,0 +1,135 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const request = require('request'); | |
4 | +const logger = require('./logger').get(); | |
5 | + | |
6 | +var config; | |
7 | +var matrix; | |
8 | +var partner; | |
9 | + | |
10 | +function init(options) { | |
11 | + config = options.config; | |
12 | + matrix = options.matrix; | |
13 | + partner = options.partner; | |
14 | + | |
15 | + initMatrix(); | |
16 | + | |
17 | + setInterval(pullTask, config.pull_interval_ms || 1000); | |
18 | +} | |
19 | + | |
20 | +function pullTask() { | |
21 | + let options = { | |
22 | + url: config.pull_url.task, | |
23 | + qs: { | |
24 | + handler: config.handler_name, | |
25 | + products: config.products.join(',') | |
26 | + } | |
27 | + } | |
28 | + | |
29 | + request(options, function(error, response, body) { | |
30 | + if (error) { | |
31 | + logger.warn('Error pulling task from CORE', {error: error}); | |
32 | + return; | |
33 | + } | |
34 | + | |
35 | + if (response.statusCode != 200) { | |
36 | + logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode}); | |
37 | + return; | |
38 | + } | |
39 | + | |
40 | + if (body == 'NONE') { | |
41 | + return; | |
42 | + } | |
43 | + | |
44 | + forwardCoreTaskToPartner(body); | |
45 | + }); | |
46 | +} | |
47 | + | |
48 | +function forwardCoreTaskToPartner(coreMessage) { | |
49 | + let task; | |
50 | + | |
51 | + try { | |
52 | + task = JSON.parse(coreMessage); | |
53 | + } | |
54 | + catch(e) { | |
55 | + logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e}); | |
56 | + } | |
57 | + | |
58 | + task.remote_product = getRemoteProduct(task.product); | |
59 | + | |
60 | + partner.buy(task); | |
61 | +} | |
62 | + | |
63 | +function report(trx_id, rc, message, sn) { | |
64 | + let options = { | |
65 | + url: config.pull_url.report, | |
66 | + qs: { | |
67 | + trx_id: trx_id, | |
68 | + rc: rc, | |
69 | + message: message, | |
70 | + handler: config.handler_name, | |
71 | + sn: sn | |
72 | + } | |
73 | + } | |
74 | + | |
75 | + request(options, function(error, response, body) { | |
76 | + if (error) { | |
77 | + logger.warn('Error reporting to CORE', {error: error}); | |
78 | + } | |
79 | + else if (response.statusCode != 200) { | |
80 | + logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode}); | |
81 | + } | |
82 | + else { | |
83 | + logger.verbose('Report has been sent to CORE', {requestOptions: options}); | |
84 | + } | |
85 | + }); | |
86 | +} | |
87 | + | |
88 | +function resendReport(trx_id, rc, message, sn) { | |
89 | + let sleepBeforeResend = 1000; | |
90 | + logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms') | |
91 | + | |
92 | + setTimeout( | |
93 | + function() { | |
94 | + report(trx_id, rc, message, sn); | |
95 | + }, | |
96 | + sleepBeforeResend | |
97 | + ) | |
98 | +} | |
99 | + | |
100 | +function isPaused() { | |
101 | + return matrix.paused; | |
102 | +} | |
103 | + | |
104 | +function pause() { | |
105 | + matrix.paused = true; | |
106 | +} | |
107 | + | |
108 | +function resume() { | |
109 | + matrix.pause = false; | |
110 | +} | |
111 | + | |
112 | +function initMatrix() { | |
113 | + if (!matrix) { | |
114 | + matrix = {}; | |
115 | + } | |
116 | + | |
117 | + matrix.counter = { | |
118 | + trx: 0 | |
119 | + } | |
120 | +} | |
121 | + | |
122 | +function incrementCounterTrx() { | |
123 | + matrix.counter.trx++; | |
124 | +} | |
125 | + | |
126 | +function getRemoteProduct(product) { | |
127 | + let remoteProduct = config.remote_products[product]; | |
128 | + return remoteProduct || product; | |
129 | +} | |
130 | + | |
131 | +exports.init = init; | |
132 | +exports.isPaused = isPaused; | |
133 | +exports.pause = pause; | |
134 | +exports.resume = resume; | |
135 | +exports.report = report; |
package.json
... | ... | @@ -0,0 +1,27 @@ |
1 | +{ | |
2 | + "name": "komodo-gw-oddeven", | |
3 | + "version": "1.0.0", | |
4 | + "description": "Contoh dummy gateway / handler komodo", | |
5 | + "main": "index.js", | |
6 | + "dependencies": { | |
7 | + "moment": "^2.17.1", | |
8 | + "request": "^2.79.0", | |
9 | + "strftime": "^0.9.2", | |
10 | + "winston": "^2.3.0", | |
11 | + "winston-daily-rotate-file": "^1.4.0" | |
12 | + }, | |
13 | + "devDependencies": {}, | |
14 | + "scripts": { | |
15 | + "test": "mocha" | |
16 | + }, | |
17 | + "repository": { | |
18 | + "type": "git", | |
19 | + "url": "git@gitlab.kodesumber.com:adhisimon/komodo-gw-oddeven.git" | |
20 | + }, | |
21 | + "keywords": [ | |
22 | + "komodo", | |
23 | + "ppob" | |
24 | + ], | |
25 | + "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", | |
26 | + "license": "ISC" | |
27 | +} |