badmfck-api-server 2.1.3 → 2.1.5
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,8 +1,9 @@
|
|
1
|
-
import { FieldInfo, MysqlError, Pool, PoolConnection } from "mysql";
|
2
1
|
import { BaseService } from "./BaseService";
|
3
2
|
import Signal, { Req } from "badmfck-signal";
|
3
|
+
import * as mysql from "mysql2/promise";
|
4
4
|
export declare const S_MYSQL_STARTED: Signal<void>;
|
5
5
|
export declare const REQ_MYSQL_QUERY: Req<MySqlQuery | MySqlQuery[], MysqlResult[]>;
|
6
|
+
export declare const REQ_MYSQL_TRANSACTION: Req<MySqlQuery[], MysqlResult>;
|
6
7
|
export declare const executeQuery: (query: MySqlQuery | MySqlQuery[]) => Promise<MysqlResult[]>;
|
7
8
|
export interface MysqlServiceOptions {
|
8
9
|
connectionLimit: number;
|
@@ -11,16 +12,24 @@ export interface MysqlServiceOptions {
|
|
11
12
|
password: string;
|
12
13
|
port: number;
|
13
14
|
database: string;
|
15
|
+
queueLimit?: number;
|
14
16
|
migrations?: {
|
15
17
|
dir: string;
|
16
18
|
callback: () => void;
|
17
19
|
} | null;
|
18
20
|
}
|
21
|
+
export interface MysqlError {
|
22
|
+
code: string;
|
23
|
+
errno: number;
|
24
|
+
sql: string;
|
25
|
+
name: string;
|
26
|
+
message: string;
|
27
|
+
fatal?: boolean;
|
28
|
+
}
|
19
29
|
export interface MysqlResult {
|
20
30
|
error?: MysqlError | null;
|
21
31
|
rollbackError?: MysqlError | null;
|
22
32
|
isDuplicateError?: boolean;
|
23
|
-
fields?: FieldInfo[] | null;
|
24
33
|
data: any;
|
25
34
|
}
|
26
35
|
export interface MySqlQuery {
|
@@ -48,7 +57,7 @@ export interface MysqlQueryFieldObject extends Record<string, string | number |
|
|
48
57
|
export declare class MysqlService extends BaseService {
|
49
58
|
reconnectionTimeout: number;
|
50
59
|
reconnecting: boolean;
|
51
|
-
pool: Pool | null;
|
60
|
+
pool: mysql.Pool | null;
|
52
61
|
options: MysqlServiceOptions;
|
53
62
|
serviceStarted: boolean;
|
54
63
|
timeoutID: any;
|
@@ -56,19 +65,18 @@ export declare class MysqlService extends BaseService {
|
|
56
65
|
constructor(options: MysqlServiceOptions);
|
57
66
|
static executeQuery(query: MySqlQuery | MySqlQuery[]): Promise<MysqlResult[]>;
|
58
67
|
init(): Promise<void>;
|
59
|
-
recreatePool(): Promise<
|
68
|
+
recreatePool(): Promise<boolean>;
|
60
69
|
onApplicationReady(): Promise<void>;
|
61
70
|
static fieldsToObject(fields: MysqlQueryField[] | MysqlQueryFieldObject, ignoreSystemParameters?: boolean): MysqlQueryFieldObject;
|
62
71
|
static objectToFields(obj: MysqlQueryFieldObject | MysqlQueryField[]): MysqlQueryField[];
|
63
72
|
static prepareQuery(query: string, fields: MysqlQueryField[] | MysqlQueryFieldObject): string;
|
64
73
|
static prepareQueryFieldValue(value: string | number | boolean | null | undefined, system?: boolean): string | number | boolean | null | undefined;
|
65
74
|
execute(query: string, rollbackQuery: string | null): Promise<MysqlResult>;
|
66
|
-
sendQuery(conn: PoolConnection, query: string, resolve: (data: MysqlResult) => void, rollback: string | null): Promise<void>;
|
67
|
-
queryAsync(conn: PoolConnection, query: string): Promise<{
|
75
|
+
sendQuery(conn: mysql.PoolConnection, query: string, resolve: (data: MysqlResult) => void, rollback: string | null): Promise<void>;
|
76
|
+
queryAsync(conn: mysql.PoolConnection, query: string): Promise<{
|
68
77
|
err: MysqlError | null;
|
69
78
|
results?: any;
|
70
|
-
fields?: FieldInfo[];
|
71
79
|
}>;
|
72
|
-
|
80
|
+
createMysqlQueryError(err: any): MysqlError;
|
73
81
|
}
|
74
82
|
export default MysqlService;
|
@@ -22,18 +22,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
22
|
__setModuleDefault(result, mod);
|
23
23
|
return result;
|
24
24
|
};
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
-
};
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
-
exports.MysqlService = exports.executeQuery = exports.REQ_MYSQL_QUERY = exports.S_MYSQL_STARTED = void 0;
|
30
|
-
const mysql_1 = __importDefault(require("mysql"));
|
26
|
+
exports.MysqlService = exports.executeQuery = exports.REQ_MYSQL_TRANSACTION = exports.REQ_MYSQL_QUERY = exports.S_MYSQL_STARTED = void 0;
|
31
27
|
const BaseService_1 = require("./BaseService");
|
32
28
|
const badmfck_signal_1 = __importStar(require("badmfck-signal"));
|
33
29
|
const crypto_1 = require("crypto");
|
34
30
|
const LogService_1 = require("./LogService");
|
31
|
+
const mysql = __importStar(require("mysql2/promise"));
|
35
32
|
exports.S_MYSQL_STARTED = new badmfck_signal_1.default();
|
36
33
|
exports.REQ_MYSQL_QUERY = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_QUERY");
|
34
|
+
exports.REQ_MYSQL_TRANSACTION = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TRANSACTION");
|
37
35
|
const executeQuery = async (query) => { return await exports.REQ_MYSQL_QUERY.request(query); };
|
38
36
|
exports.executeQuery = executeQuery;
|
39
37
|
class MysqlService extends BaseService_1.BaseService {
|
@@ -58,8 +56,33 @@ class MysqlService extends BaseService_1.BaseService {
|
|
58
56
|
}
|
59
57
|
static async executeQuery(query) { return await exports.REQ_MYSQL_QUERY.request(query); }
|
60
58
|
async init() {
|
59
|
+
super.init();
|
60
|
+
process.on('SIGINT', async () => {
|
61
|
+
console.log('1. Received SIGINT. Performing cleanup...');
|
62
|
+
if (this.pool) {
|
63
|
+
try {
|
64
|
+
await this.pool.end();
|
65
|
+
}
|
66
|
+
catch (e) {
|
67
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't close MYSQL pool!");
|
68
|
+
}
|
69
|
+
}
|
70
|
+
process.exit(0);
|
71
|
+
});
|
72
|
+
process.on('SIGTERM', () => {
|
73
|
+
console.log('2. Received SIGTERM. Performing cleanup...');
|
74
|
+
process.exit(0);
|
75
|
+
});
|
61
76
|
this.serviceStarted = false;
|
62
|
-
|
77
|
+
let poolCreated = false;
|
78
|
+
while (!poolCreated) {
|
79
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "Connecting to MYSQL!");
|
80
|
+
poolCreated = await this.recreatePool();
|
81
|
+
if (!poolCreated) {
|
82
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't connect to MYSQL! Retrying in 3 seconds...");
|
83
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
84
|
+
}
|
85
|
+
}
|
63
86
|
exports.REQ_MYSQL_QUERY.listener = async (data) => {
|
64
87
|
if (!Array.isArray(data))
|
65
88
|
data = [data];
|
@@ -70,22 +93,97 @@ class MysqlService extends BaseService_1.BaseService {
|
|
70
93
|
}
|
71
94
|
return await Promise.all(promises);
|
72
95
|
};
|
96
|
+
exports.REQ_MYSQL_TRANSACTION.listener = async (data) => {
|
97
|
+
if (!this.pool)
|
98
|
+
return { error: { code: "NO_POOL", errno: 100000, fatal: true, sql: "", name: "NO_POOL", message: "Mysql pool not created" }, data: null };
|
99
|
+
const conn = await this.pool.getConnection();
|
100
|
+
if (!conn)
|
101
|
+
return { error: { code: "NO_CONN", errno: 100001, fatal: true, sql: "", name: "NO_CONN", message: "Mysql pool cant get connection" }, data: null };
|
102
|
+
let result = null;
|
103
|
+
let income = [];
|
104
|
+
try {
|
105
|
+
await conn.beginTransaction();
|
106
|
+
await conn.query("SET autocommit=0");
|
107
|
+
for (let i of data) {
|
108
|
+
const d = await conn.query(MysqlService.prepareQuery(i.query, i.fields));
|
109
|
+
income.push(d[0]);
|
110
|
+
}
|
111
|
+
await conn.commit();
|
112
|
+
}
|
113
|
+
catch (e) {
|
114
|
+
let rollbackError = null;
|
115
|
+
try {
|
116
|
+
await conn.rollback();
|
117
|
+
}
|
118
|
+
catch (e2) {
|
119
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't rollback transaction!");
|
120
|
+
rollbackError = this.createMysqlQueryError(e2);
|
121
|
+
}
|
122
|
+
result = { error: this.createMysqlQueryError(e), data: null, rollbackError: rollbackError };
|
123
|
+
}
|
124
|
+
try {
|
125
|
+
conn.release();
|
126
|
+
}
|
127
|
+
catch (e) { }
|
128
|
+
if (!result)
|
129
|
+
result = { error: null, data: income };
|
130
|
+
return result;
|
131
|
+
};
|
73
132
|
}
|
74
133
|
async recreatePool() {
|
75
|
-
(0, LogService_1.logInfo)("${MysqlService.js}", "
|
76
|
-
this.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
134
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "Connecting to mysql: \n HOST: " + this.options.host + '\n PORT:' + this.options.port);
|
135
|
+
if (this.pool) {
|
136
|
+
this.pool.removeAllListeners();
|
137
|
+
try {
|
138
|
+
await this.pool.end();
|
139
|
+
}
|
140
|
+
catch (e) {
|
141
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't close MYSQL pool!");
|
142
|
+
}
|
143
|
+
this.pool = null;
|
83
144
|
}
|
84
|
-
|
85
|
-
this.
|
86
|
-
|
87
|
-
|
145
|
+
try {
|
146
|
+
this.pool = mysql.createPool({
|
147
|
+
host: this.options.host,
|
148
|
+
user: this.options.user,
|
149
|
+
password: this.options.password,
|
150
|
+
database: this.options.database,
|
151
|
+
port: this.options.port,
|
152
|
+
connectionLimit: this.options.connectionLimit,
|
153
|
+
queueLimit: 10
|
154
|
+
});
|
155
|
+
}
|
156
|
+
catch (e) {
|
157
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't connect to MYSQL!");
|
158
|
+
return false;
|
88
159
|
}
|
160
|
+
this.pool?.on('connection', (connection) => {
|
161
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "MYSQL CONNECTION CREATED");
|
162
|
+
});
|
163
|
+
this.pool?.on('acquire', (connection) => {
|
164
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "MYSQL CONNECTION ACQUIRED");
|
165
|
+
});
|
166
|
+
this.pool?.on('release', (connection) => {
|
167
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "MYSQL CONNECTION RELEASED");
|
168
|
+
});
|
169
|
+
this.pool?.on('enqueue', () => {
|
170
|
+
(0, LogService_1.logInfo)("${MysqlService.js}", "MYSQL CONNECTION ENQUEUED");
|
171
|
+
});
|
172
|
+
return new Promise(async (resolve, reject) => {
|
173
|
+
try {
|
174
|
+
const conn = await this.pool?.getConnection();
|
175
|
+
if (conn) {
|
176
|
+
conn?.release();
|
177
|
+
resolve(true);
|
178
|
+
}
|
179
|
+
else
|
180
|
+
resolve(false);
|
181
|
+
}
|
182
|
+
catch (e) {
|
183
|
+
(0, LogService_1.logCrit)("${MysqlService.js}", "Can't connect to MYSQL!");
|
184
|
+
resolve(false);
|
185
|
+
}
|
186
|
+
});
|
89
187
|
}
|
90
188
|
async onApplicationReady() { }
|
91
189
|
static fieldsToObject(fields, ignoreSystemParameters) {
|
@@ -207,7 +305,7 @@ class MysqlService extends BaseService_1.BaseService {
|
|
207
305
|
return value;
|
208
306
|
}
|
209
307
|
async execute(query, rollbackQuery) {
|
210
|
-
return new Promise((resolve, reject) => {
|
308
|
+
return new Promise(async (resolve, reject) => {
|
211
309
|
if (!this.pool) {
|
212
310
|
(0, LogService_1.logError)("${MysqlService.js}", "No pool");
|
213
311
|
resolve({
|
@@ -220,23 +318,11 @@ class MysqlService extends BaseService_1.BaseService {
|
|
220
318
|
message: "Mysql pool not created"
|
221
319
|
},
|
222
320
|
data: null,
|
223
|
-
fields: null
|
224
321
|
});
|
225
322
|
return;
|
226
323
|
}
|
227
|
-
|
228
|
-
|
229
|
-
(0, LogService_1.logError)("${MysqlService.js}", err);
|
230
|
-
if (`${err}`.indexOf('ECONNREFUSED') !== -1) {
|
231
|
-
this.recreatePool();
|
232
|
-
}
|
233
|
-
resolve({
|
234
|
-
error: err,
|
235
|
-
data: null,
|
236
|
-
fields: null
|
237
|
-
});
|
238
|
-
return;
|
239
|
-
}
|
324
|
+
try {
|
325
|
+
const conn = await this.pool.getConnection();
|
240
326
|
if (!conn) {
|
241
327
|
(0, LogService_1.logCrit)("${MysqlService.js}", `No connection created!`);
|
242
328
|
resolve({
|
@@ -249,11 +335,28 @@ class MysqlService extends BaseService_1.BaseService {
|
|
249
335
|
message: "Mysql pool cant get connection"
|
250
336
|
},
|
251
337
|
data: null,
|
252
|
-
fields: null
|
253
338
|
});
|
339
|
+
return;
|
254
340
|
}
|
255
341
|
this.sendQuery(conn, query, resolve, rollbackQuery);
|
256
|
-
}
|
342
|
+
}
|
343
|
+
catch (e) {
|
344
|
+
(0, LogService_1.logError)("${MysqlService.js}", e);
|
345
|
+
if (`${e}`.indexOf('ECONNREFUSED') !== -1)
|
346
|
+
this.recreatePool();
|
347
|
+
resolve({
|
348
|
+
error: {
|
349
|
+
code: "NO_CONN",
|
350
|
+
errno: 100001,
|
351
|
+
fatal: true,
|
352
|
+
sql: query,
|
353
|
+
name: "NO_CONN",
|
354
|
+
message: (e && typeof e === "object" && "message" in e) ? e.message : "Mysql cant get connection"
|
355
|
+
},
|
356
|
+
data: null
|
357
|
+
});
|
358
|
+
return;
|
359
|
+
}
|
257
360
|
});
|
258
361
|
}
|
259
362
|
async sendQuery(conn, query, resolve, rollback) {
|
@@ -279,7 +382,6 @@ class MysqlService extends BaseService_1.BaseService {
|
|
279
382
|
message: "Error: " + err
|
280
383
|
},
|
281
384
|
data: null,
|
282
|
-
fields: null,
|
283
385
|
rollbackError: rollbackError
|
284
386
|
});
|
285
387
|
});
|
@@ -299,7 +401,6 @@ class MysqlService extends BaseService_1.BaseService {
|
|
299
401
|
resolve({
|
300
402
|
error: queryResult.err,
|
301
403
|
data: null,
|
302
|
-
fields: null,
|
303
404
|
rollbackError: rollbackError,
|
304
405
|
isDuplicateError: dup
|
305
406
|
});
|
@@ -312,87 +413,40 @@ class MysqlService extends BaseService_1.BaseService {
|
|
312
413
|
resolve({
|
313
414
|
error: queryResult.err,
|
314
415
|
data: queryResult.results,
|
315
|
-
fields: queryResult.fields
|
316
416
|
});
|
317
417
|
}
|
318
418
|
async queryAsync(conn, query) {
|
319
|
-
return new Promise((resolve, reject) => {
|
320
|
-
try {
|
321
|
-
conn.query(query, (err, results, fields) => {
|
322
|
-
resolve({
|
323
|
-
err: err,
|
324
|
-
results: results,
|
325
|
-
fields: fields
|
326
|
-
});
|
327
|
-
});
|
328
|
-
}
|
329
|
-
catch (e) {
|
330
|
-
resolve({
|
331
|
-
err: {
|
332
|
-
code: "QUERY_ERR",
|
333
|
-
errno: 100002,
|
334
|
-
fatal: true,
|
335
|
-
sql: query,
|
336
|
-
name: "QUERY_ERR",
|
337
|
-
message: "Error: " + e
|
338
|
-
}
|
339
|
-
});
|
340
|
-
}
|
341
|
-
});
|
342
|
-
}
|
343
|
-
async createPool() {
|
344
|
-
(0, LogService_1.logInfo)("${MysqlService.js}", "Connecting to mysql: \n HOST: " + this.options.host + '\n PORT:' + this.options.port);
|
345
|
-
let err = false;
|
346
|
-
if (this.pool) {
|
347
|
-
try {
|
348
|
-
this.pool.removeAllListeners();
|
349
|
-
this.pool.end(err => {
|
350
|
-
if (err)
|
351
|
-
(0, LogService_1.logError)("${MysqlService.js}", err);
|
352
|
-
});
|
353
|
-
}
|
354
|
-
catch (e) {
|
355
|
-
(0, LogService_1.logCrit)("${MysqlService.js}", e);
|
356
|
-
}
|
357
|
-
}
|
358
419
|
try {
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
port: this.options.port,
|
365
|
-
database: this.options.database,
|
366
|
-
multipleStatements: true
|
367
|
-
});
|
420
|
+
const result = await conn.query(query);
|
421
|
+
return {
|
422
|
+
err: null,
|
423
|
+
results: result[0],
|
424
|
+
};
|
368
425
|
}
|
369
426
|
catch (e) {
|
370
|
-
|
371
|
-
err = true;
|
427
|
+
return { err: this.createMysqlQueryError(e) };
|
372
428
|
}
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
429
|
+
}
|
430
|
+
createMysqlQueryError(err) {
|
431
|
+
if (err && typeof err === "object" && "code" in err && "errno" in err && "sql" in err && "name" in err && "message" in err) {
|
432
|
+
return {
|
433
|
+
code: err.code,
|
434
|
+
errno: err.errno,
|
435
|
+
sql: err.sql,
|
436
|
+
name: err.name,
|
437
|
+
message: err.message
|
438
|
+
};
|
439
|
+
}
|
440
|
+
else {
|
441
|
+
return {
|
442
|
+
code: "QUERY_ERR",
|
443
|
+
errno: 100002,
|
444
|
+
fatal: true,
|
445
|
+
sql: "no query",
|
446
|
+
name: "QUERY_ERR",
|
447
|
+
message: "Error: " + (err) ? err : ""
|
448
|
+
};
|
377
449
|
}
|
378
|
-
return new Promise((res, rej) => {
|
379
|
-
if (err) {
|
380
|
-
res(false);
|
381
|
-
return;
|
382
|
-
}
|
383
|
-
if (!this.pool) {
|
384
|
-
res(false);
|
385
|
-
return;
|
386
|
-
}
|
387
|
-
this.pool.getConnection((e, cnn) => {
|
388
|
-
if (e) {
|
389
|
-
(0, LogService_1.logError)("${MysqlService.js}", e.message);
|
390
|
-
res(false);
|
391
|
-
return;
|
392
|
-
}
|
393
|
-
res(true);
|
394
|
-
});
|
395
|
-
});
|
396
450
|
}
|
397
451
|
}
|
398
452
|
exports.MysqlService = MysqlService;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "badmfck-api-server",
|
3
|
-
"version": "2.1.
|
3
|
+
"version": "2.1.5",
|
4
4
|
"description": "Simple API http server based on express",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -25,7 +25,7 @@
|
|
25
25
|
"cors": "^2.8.5",
|
26
26
|
"express": "^4.19.2",
|
27
27
|
"express-fileupload": "^1.5.0",
|
28
|
-
"
|
28
|
+
"mysql2": "^3.11.3",
|
29
29
|
"ws": "^8.18.0"
|
30
30
|
},
|
31
31
|
"devDependencies": {
|