anote-server-libs 0.2.2 → 0.2.3

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.
@@ -1,134 +1,134 @@
1
- import {NextFunction, Request, Response} from 'express';
2
- import {Logger} from 'winston';
3
- import {BaseModelRepository} from '../models/repository/BaseModelRepository';
4
- import {jsonStringify, utils} from './utils';
5
-
6
- export const enum SystemLock {
7
- CHECK_CROSSING = 1,
8
- FLUSH_CALLS = 2
9
- }
10
-
11
- export function withTransaction(repo: BaseModelRepository, logger: Logger, previousMethod: (req: Request, res: Response, next: NextFunction) => void, lock?: SystemLock) {
12
- return function(req: Request, res: Response, next: NextFunction) {
13
- const endTerminator = res.end.bind(res);
14
- const jsonTerminator = (obj: any) => {
15
- res.write(jsonStringify(obj) || '{}');
16
- endTerminator();
17
- };
18
- const connectTimeoutHandler = setTimeout(() => {
19
- // Timed out getting a client, restart worker or process...
20
- logger.error('Error timed out getting a client, exiting...');
21
- process.exit(22);
22
- }, 3000);
23
- Promise.all([
24
- repo.db ? repo.db.connect() : Promise.resolve(undefined),
25
- repo.dbMssql ? Promise.resolve(repo.dbMssql.transaction()) : Promise.resolve(undefined)
26
- ]).then(([c1, c2]) => {
27
- const dbClient = c1 || c2;
28
- clearTimeout(connectTimeoutHandler);
29
- // On error, will rollback...
30
- utils.logger = logger;
31
- dbClient.removeListener('error', utils.clientErrorHandler);
32
- dbClient.on('error', utils.clientErrorHandler);
33
-
34
- res.locals.dbClient = dbClient;
35
- res.locals.dbClientCommited = false;
36
- res.locals.dbClientCommit = (cb: (err: any) => any) => {
37
- if(!res.locals.dbClientCommited) {
38
- res.locals.dbClientCommited = true;
39
- (repo.db ? dbClient.query('COMMIT') : dbClient.commit()).catch((err: any) => err).then((err: any) => {
40
- if(repo.db) dbClient.release();
41
- if(!(err instanceof Error)) {
42
- for(let i = 0; i < res.locals.dbClientOnCommit.length; i++) {
43
- res.locals.dbClientOnCommit[i]();
44
- }
45
- }
46
- cb(err instanceof Error ? err : undefined);
47
- });
48
- } else {
49
- cb(undefined);
50
- }
51
- };
52
- res.locals.dbClientOnCommit = [];
53
- return (repo.db ? dbClient.query('BEGIN') : dbClient.begin()).then(() => {
54
- const finish = () => {
55
- res.json = (obj: any) => {
56
- if(res.statusCode > 303 && res.statusCode !== 412) {
57
- if(logger && res.statusCode > 499) {
58
- logger.error('Uncaught 500: %j', obj.error.additionalInfo);
59
- }
60
- (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch((err: any) => obj.error.additionalInfo2 = {message: err.message}).then(() => {
61
- if(repo.db) dbClient.release();
62
- jsonTerminator(obj);
63
- });
64
- } else {
65
- res.locals.dbClientCommit((err: any) => {
66
- if(err) {
67
- res.status(500);
68
- jsonTerminator({
69
- error: {
70
- errorKey: 'internal.db',
71
- additionalInfo: {message: err.message}
72
- }
73
- });
74
- } else jsonTerminator(obj);
75
- });
76
- }
77
- return res;
78
- };
79
- res.end = () => {
80
- if(res.statusCode > 303 && res.statusCode !== 412) {
81
- if(logger && res.statusCode > 499) {
82
- logger.error('Uncaught 500 with no details...');
83
- }
84
- (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch((): any => undefined).then(() => {
85
- if(repo.db) dbClient.release();
86
- endTerminator();
87
- });
88
- } else {
89
- res.locals.dbClientCommit((err: any) => {
90
- if(err) {
91
- res.status(500);
92
- jsonTerminator({
93
- error: {
94
- errorKey: 'internal.db',
95
- additionalInfo: {message: err.message}
96
- }
97
- });
98
- } else endTerminator();
99
- });
100
- }
101
- return res;
102
- };
103
- return previousMethod.call(this, req, res, next);
104
- };
105
-
106
- if(lock) {
107
- dbClient.query('SELECT pg_advisory_xact_lock(' + lock + ')').then(() => finish()).catch((err: any) => {
108
- res.status(500).json({
109
- error: {
110
- errorKey: 'internal.db',
111
- additionalInfo: {message: err.message}
112
- }
113
- });
114
- dbClient.release();
115
- });
116
- } else {
117
- finish();
118
- }
119
- }).catch((err: any) => {
120
- if(repo.db) dbClient.release();
121
- else dbClient.rollback();
122
- throw err;
123
- });
124
- }).catch(err => {
125
- // Error connecting to database, restarting worker after the timeout as well...
126
- res.status(500).json({
127
- error: {
128
- errorKey: 'internal.db',
129
- additionalInfo: {message: err.message}
130
- }
131
- });
132
- });
133
- };
134
- }
1
+ import {NextFunction, Request, Response} from 'express';
2
+ import {Logger} from 'winston';
3
+ import {BaseModelRepository} from '../models/repository/BaseModelRepository';
4
+ import {jsonStringify, utils} from './utils';
5
+
6
+ export const enum SystemLock {
7
+ CHECK_CROSSING = 1,
8
+ FLUSH_CALLS = 2
9
+ }
10
+
11
+ export function withTransaction(repo: BaseModelRepository, logger: Logger, previousMethod: (req: Request, res: Response, next: NextFunction) => void, lock?: SystemLock) {
12
+ return function(req: Request, res: Response, next: NextFunction) {
13
+ const endTerminator = res.end.bind(res);
14
+ const jsonTerminator = (obj: any) => {
15
+ res.write(jsonStringify(obj) || '{}');
16
+ endTerminator();
17
+ };
18
+ const connectTimeoutHandler = setTimeout(() => {
19
+ // Timed out getting a client, restart worker or process...
20
+ logger.error('Error timed out getting a client, exiting...');
21
+ process.exit(22);
22
+ }, 3000);
23
+ Promise.all([
24
+ repo.db ? repo.db.connect() : Promise.resolve(undefined),
25
+ repo.dbMssql ? Promise.resolve(repo.dbMssql.transaction()) : Promise.resolve(undefined)
26
+ ]).then(([c1, c2]) => {
27
+ const dbClient = c1 || c2;
28
+ clearTimeout(connectTimeoutHandler);
29
+ // On error, will rollback...
30
+ utils.logger = logger;
31
+ dbClient.removeListener('error', utils.clientErrorHandler);
32
+ dbClient.on('error', utils.clientErrorHandler);
33
+
34
+ res.locals.dbClient = dbClient;
35
+ res.locals.dbClientCommited = false;
36
+ res.locals.dbClientCommit = (cb: (err: any) => any) => {
37
+ if(!res.locals.dbClientCommited) {
38
+ res.locals.dbClientCommited = true;
39
+ (repo.db ? dbClient.query('COMMIT') : dbClient.commit()).catch((err: any) => err).then((err: any) => {
40
+ if(repo.db) dbClient.release();
41
+ if(!(err instanceof Error)) {
42
+ for(let i = 0; i < res.locals.dbClientOnCommit.length; i++) {
43
+ res.locals.dbClientOnCommit[i]();
44
+ }
45
+ }
46
+ cb(err instanceof Error ? err : undefined);
47
+ });
48
+ } else {
49
+ cb(undefined);
50
+ }
51
+ };
52
+ res.locals.dbClientOnCommit = [];
53
+ return (repo.db ? dbClient.query('BEGIN') : dbClient.begin()).then(() => {
54
+ const finish = () => {
55
+ res.json = (obj: any) => {
56
+ if(res.statusCode > 303 && res.statusCode !== 412) {
57
+ if(logger && res.statusCode > 499) {
58
+ logger.error('Uncaught 500: %j', obj.error.additionalInfo);
59
+ }
60
+ (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch((err: any) => obj.error.additionalInfo2 = {message: err.message}).then(() => {
61
+ if(repo.db) dbClient.release();
62
+ jsonTerminator(obj);
63
+ });
64
+ } else {
65
+ res.locals.dbClientCommit((err: any) => {
66
+ if(err) {
67
+ res.status(500);
68
+ jsonTerminator({
69
+ error: {
70
+ errorKey: 'internal.db',
71
+ additionalInfo: {message: err.message}
72
+ }
73
+ });
74
+ } else jsonTerminator(obj);
75
+ });
76
+ }
77
+ return res;
78
+ };
79
+ res.end = () => {
80
+ if(res.statusCode > 303 && res.statusCode !== 412) {
81
+ if(logger && res.statusCode > 499) {
82
+ logger.error('Uncaught 500 with no details...');
83
+ }
84
+ (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch((): any => undefined).then(() => {
85
+ if(repo.db) dbClient.release();
86
+ endTerminator();
87
+ });
88
+ } else {
89
+ res.locals.dbClientCommit((err: any) => {
90
+ if(err) {
91
+ res.status(500);
92
+ jsonTerminator({
93
+ error: {
94
+ errorKey: 'internal.db',
95
+ additionalInfo: {message: err.message}
96
+ }
97
+ });
98
+ } else endTerminator();
99
+ });
100
+ }
101
+ return res;
102
+ };
103
+ return previousMethod.call(this, req, res, next);
104
+ };
105
+
106
+ if(lock) {
107
+ dbClient.query('SELECT pg_advisory_xact_lock(' + lock + ')').then(() => finish()).catch((err: any) => {
108
+ res.status(500).json({
109
+ error: {
110
+ errorKey: 'internal.db',
111
+ additionalInfo: {message: err.message}
112
+ }
113
+ });
114
+ dbClient.release();
115
+ });
116
+ } else {
117
+ finish();
118
+ }
119
+ }).catch((err: any) => {
120
+ if(repo.db) dbClient.release();
121
+ else dbClient.rollback();
122
+ throw err;
123
+ });
124
+ }).catch(err => {
125
+ // Error connecting to database, restarting worker after the timeout as well...
126
+ res.status(500).json({
127
+ error: {
128
+ errorKey: 'internal.db',
129
+ additionalInfo: {message: err.message}
130
+ }
131
+ });
132
+ });
133
+ };
134
+ }
package/services/utils.js CHANGED
@@ -1,197 +1,197 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.digitize = exports.fpEuros = exports.sendSelfPostableMessage = exports.idempotent = exports.jsonStringify = exports.lcm = exports.gcd = exports.utils = exports.clientErrorHandle = exports.btoa = exports.atob = void 0;
4
- function atob(str) {
5
- return Buffer.from(str, 'base64').toString('binary');
6
- }
7
- exports.atob = atob;
8
- function btoa(str) {
9
- return Buffer.from(str).toString('base64');
10
- }
11
- exports.btoa = btoa;
12
- function clientErrorHandle(err) {
13
- this.error('Error on DB client: %j', err);
14
- }
15
- exports.clientErrorHandle = clientErrorHandle;
16
- exports.utils = {
17
- clientErrorHandler: undefined
18
- };
19
- function gcdTwo(a, b) {
20
- if (a === 0)
21
- return b;
22
- return gcdTwo(b % a, a);
23
- }
24
- function gcd(values) {
25
- let result = values[0];
26
- for (let i = 1; i < values.length; i++)
27
- result = gcdTwo(values[i], result);
28
- return result;
29
- }
30
- exports.gcd = gcd;
31
- function lcm(values) {
32
- let l = 1, divisor = 2;
33
- while (true) {
34
- let counter = 0;
35
- let divisible = false;
36
- for (let i = 0; i < values.length; i++) {
37
- if (values[i] === 0) {
38
- return 0;
39
- }
40
- else if (values[i] < 0) {
41
- values[i] = values[i] * (-1);
42
- }
43
- if (values[i] === 1) {
44
- counter++;
45
- }
46
- if (values[i] % divisor === 0) {
47
- divisible = true;
48
- values[i] = values[i] / divisor;
49
- }
50
- }
51
- if (divisible) {
52
- l = l * divisor;
53
- }
54
- else {
55
- divisor++;
56
- }
57
- if (counter === values.length) {
58
- return l;
59
- }
60
- }
61
- }
62
- exports.lcm = lcm;
63
- function jsonStringify(obj) {
64
- const cache = {};
65
- return JSON.stringify(obj, function (_, value) {
66
- if (typeof value === 'object' && value !== null) {
67
- if (cache[value] !== -1) {
68
- try {
69
- return JSON.parse(JSON.stringify(value));
70
- }
71
- catch (error) {
72
- return;
73
- }
74
- }
75
- cache[value] = true;
76
- }
77
- return value;
78
- });
79
- }
80
- exports.jsonStringify = jsonStringify;
81
- function idempotent(repo, debug, logger) {
82
- return function (req, res, next) {
83
- let idempotenceKey = req.header('x-idempotent-key');
84
- if (idempotenceKey) {
85
- idempotenceKey = idempotenceKey.substring(0, 40);
86
- repo.ApiCall.get(idempotenceKey).then(call => {
87
- if (!call) {
88
- const jsonTerminator = res.json;
89
- const endTerminator = res.end;
90
- const writeTerminator = res.write;
91
- let response = '';
92
- res.json = (function (obj) {
93
- repo.ApiCall.create({
94
- id: idempotenceKey,
95
- responseCode: res.statusCode,
96
- responseJson: jsonStringify(obj),
97
- expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
98
- }).then(() => jsonTerminator.call(res, obj), err => {
99
- if (err)
100
- logger.warn('Cannot save idempotent key: %j', err);
101
- jsonTerminator.call(res, obj);
102
- });
103
- }).bind(res);
104
- res.end = (function (buf) {
105
- if (buf)
106
- response = response + buf.toString();
107
- repo.ApiCall.create({
108
- id: idempotenceKey,
109
- responseCode: res.statusCode,
110
- responseJson: response,
111
- expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
112
- }).then(() => endTerminator.call(res, buf), err => {
113
- if (err)
114
- logger.warn('Cannot save idempotent key: %j', err);
115
- endTerminator.call(res, buf);
116
- });
117
- }).bind(res);
118
- res.write = (function (buf) {
119
- if (buf)
120
- response = response + buf.toString();
121
- writeTerminator.call(res, buf);
122
- }).bind(res);
123
- next();
124
- }
125
- else
126
- res.status(417).json({
127
- responseCode: call.responseCode,
128
- responseBody: call.responseJson
129
- });
130
- }, err => res.status(500).json({
131
- error: {
132
- errorKey: 'internal.db',
133
- additionalInfo: { message: err.message, stack: debug && err.stack }
134
- }
135
- }));
136
- }
137
- else
138
- next();
139
- };
140
- }
141
- exports.idempotent = idempotent;
142
- function sendSelfPostableMessage(res, code, messageType, err) {
143
- res.type('text/html').status(code).write(`
144
- <!DOCTYPE HTML>
145
- <html>
146
- <head>
147
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
148
- </head>
149
- <body>
150
- <script type="text/javascript">
151
- window.parent.postMessage({
152
- type: '${messageType}',
153
- confirm: ${!err},
154
- error: JSON.parse('${JSON.stringify(err) || 'null'}')
155
- }, '*');
156
- </script>
157
- </body>
158
- </html>
159
- `);
160
- res.end();
161
- }
162
- exports.sendSelfPostableMessage = sendSelfPostableMessage;
163
- function fpEuros(n) {
164
- return Math.round(n * 100) / 100;
165
- }
166
- exports.fpEuros = fpEuros;
167
- function digitize(value, opts) {
168
- if (value === undefined || value === null)
169
- return 'undefined';
170
- if (typeof value === 'number') {
171
- if (isNaN(value))
172
- return '-';
173
- if (!isFinite(value))
174
- return 'Infinite';
175
- value = String(value);
176
- }
177
- else if (typeof value === 'string')
178
- return value;
179
- const parts = value.split('.');
180
- const initialLength = parts[0].length;
181
- for (let i = initialLength - 3; i > 0; i -= 3) {
182
- parts[0] = parts[0].slice(0, i) + ',' + parts[0].slice(i);
183
- }
184
- if (parts[0].startsWith('-,'))
185
- parts[0] = '-' + parts[0].slice(2);
186
- if (parts[1]) {
187
- const expDecimals = parts[1].split(/[eE]-/);
188
- if (expDecimals.length > 1 && parseInt(expDecimals[1], 10) > 2)
189
- return '0.00';
190
- let decimals = fpEuros(parseFloat('0.' + parts[1])).toString().substr(2, 2);
191
- if (decimals.length === 1)
192
- decimals += '0';
193
- return parts[0] + '.' + decimals;
194
- }
195
- return (opts && opts.currency) ? (parts[0] + '.00') : parts[0];
196
- }
197
- exports.digitize = digitize;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.digitize = exports.fpEuros = exports.sendSelfPostableMessage = exports.idempotent = exports.jsonStringify = exports.lcm = exports.gcd = exports.utils = exports.clientErrorHandle = exports.btoa = exports.atob = void 0;
4
+ function atob(str) {
5
+ return Buffer.from(str, 'base64').toString('binary');
6
+ }
7
+ exports.atob = atob;
8
+ function btoa(str) {
9
+ return Buffer.from(str).toString('base64');
10
+ }
11
+ exports.btoa = btoa;
12
+ function clientErrorHandle(err) {
13
+ this.error('Error on DB client: %j', err);
14
+ }
15
+ exports.clientErrorHandle = clientErrorHandle;
16
+ exports.utils = {
17
+ clientErrorHandler: undefined
18
+ };
19
+ function gcdTwo(a, b) {
20
+ if (a === 0)
21
+ return b;
22
+ return gcdTwo(b % a, a);
23
+ }
24
+ function gcd(values) {
25
+ let result = values[0];
26
+ for (let i = 1; i < values.length; i++)
27
+ result = gcdTwo(values[i], result);
28
+ return result;
29
+ }
30
+ exports.gcd = gcd;
31
+ function lcm(values) {
32
+ let l = 1, divisor = 2;
33
+ while (true) {
34
+ let counter = 0;
35
+ let divisible = false;
36
+ for (let i = 0; i < values.length; i++) {
37
+ if (values[i] === 0) {
38
+ return 0;
39
+ }
40
+ else if (values[i] < 0) {
41
+ values[i] = values[i] * (-1);
42
+ }
43
+ if (values[i] === 1) {
44
+ counter++;
45
+ }
46
+ if (values[i] % divisor === 0) {
47
+ divisible = true;
48
+ values[i] = values[i] / divisor;
49
+ }
50
+ }
51
+ if (divisible) {
52
+ l = l * divisor;
53
+ }
54
+ else {
55
+ divisor++;
56
+ }
57
+ if (counter === values.length) {
58
+ return l;
59
+ }
60
+ }
61
+ }
62
+ exports.lcm = lcm;
63
+ function jsonStringify(obj) {
64
+ const cache = {};
65
+ return JSON.stringify(obj, function (_, value) {
66
+ if (typeof value === 'object' && value !== null) {
67
+ if (cache[value] !== -1) {
68
+ try {
69
+ return JSON.parse(JSON.stringify(value));
70
+ }
71
+ catch (error) {
72
+ return;
73
+ }
74
+ }
75
+ cache[value] = true;
76
+ }
77
+ return value;
78
+ });
79
+ }
80
+ exports.jsonStringify = jsonStringify;
81
+ function idempotent(repo, debug, logger) {
82
+ return function (req, res, next) {
83
+ let idempotenceKey = req.header('x-idempotent-key');
84
+ if (idempotenceKey) {
85
+ idempotenceKey = idempotenceKey.substring(0, 40);
86
+ repo.ApiCall.get(idempotenceKey).then(call => {
87
+ if (!call) {
88
+ const jsonTerminator = res.json;
89
+ const endTerminator = res.end;
90
+ const writeTerminator = res.write;
91
+ let response = '';
92
+ res.json = (function (obj) {
93
+ repo.ApiCall.create({
94
+ id: idempotenceKey,
95
+ responseCode: res.statusCode,
96
+ responseJson: jsonStringify(obj),
97
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
98
+ }).then(() => jsonTerminator.call(res, obj), err => {
99
+ if (err)
100
+ logger.warn('Cannot save idempotent key: %j', err);
101
+ jsonTerminator.call(res, obj);
102
+ });
103
+ }).bind(res);
104
+ res.end = (function (buf) {
105
+ if (buf)
106
+ response = response + buf.toString();
107
+ repo.ApiCall.create({
108
+ id: idempotenceKey,
109
+ responseCode: res.statusCode,
110
+ responseJson: response,
111
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
112
+ }).then(() => endTerminator.call(res, buf), err => {
113
+ if (err)
114
+ logger.warn('Cannot save idempotent key: %j', err);
115
+ endTerminator.call(res, buf);
116
+ });
117
+ }).bind(res);
118
+ res.write = (function (buf) {
119
+ if (buf)
120
+ response = response + buf.toString();
121
+ writeTerminator.call(res, buf);
122
+ }).bind(res);
123
+ next();
124
+ }
125
+ else
126
+ res.status(417).json({
127
+ responseCode: call.responseCode,
128
+ responseBody: call.responseJson
129
+ });
130
+ }, err => res.status(500).json({
131
+ error: {
132
+ errorKey: 'internal.db',
133
+ additionalInfo: { message: err.message, stack: debug && err.stack }
134
+ }
135
+ }));
136
+ }
137
+ else
138
+ next();
139
+ };
140
+ }
141
+ exports.idempotent = idempotent;
142
+ function sendSelfPostableMessage(res, code, messageType, err) {
143
+ res.type('text/html').status(code).write(`
144
+ <!DOCTYPE HTML>
145
+ <html>
146
+ <head>
147
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
148
+ </head>
149
+ <body>
150
+ <script type="text/javascript">
151
+ window.parent.postMessage({
152
+ type: '${messageType}',
153
+ confirm: ${!err},
154
+ error: JSON.parse('${JSON.stringify(err) || 'null'}')
155
+ }, '*');
156
+ </script>
157
+ </body>
158
+ </html>
159
+ `);
160
+ res.end();
161
+ }
162
+ exports.sendSelfPostableMessage = sendSelfPostableMessage;
163
+ function fpEuros(n) {
164
+ return Math.round(n * 100) / 100;
165
+ }
166
+ exports.fpEuros = fpEuros;
167
+ function digitize(value, opts) {
168
+ if (value === undefined || value === null)
169
+ return 'undefined';
170
+ if (typeof value === 'number') {
171
+ if (isNaN(value))
172
+ return '-';
173
+ if (!isFinite(value))
174
+ return 'Infinite';
175
+ value = String(value);
176
+ }
177
+ else if (typeof value === 'string')
178
+ return value;
179
+ const parts = value.split('.');
180
+ const initialLength = parts[0].length;
181
+ for (let i = initialLength - 3; i > 0; i -= 3) {
182
+ parts[0] = parts[0].slice(0, i) + ',' + parts[0].slice(i);
183
+ }
184
+ if (parts[0].startsWith('-,'))
185
+ parts[0] = '-' + parts[0].slice(2);
186
+ if (parts[1]) {
187
+ const expDecimals = parts[1].split(/[eE]-/);
188
+ if (expDecimals.length > 1 && parseInt(expDecimals[1], 10) > 2)
189
+ return '0.00';
190
+ let decimals = fpEuros(parseFloat('0.' + parts[1])).toString().substr(2, 2);
191
+ if (decimals.length === 1)
192
+ decimals += '0';
193
+ return parts[0] + '.' + decimals;
194
+ }
195
+ return (opts && opts.currency) ? (parts[0] + '.00') : parts[0];
196
+ }
197
+ exports.digitize = digitize;