badmfck-api-server 2.1.3 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -83,7 +83,7 @@ async function Initializer(services) {
83
83
  exports.Initializer = Initializer;
84
84
  class APIService extends BaseService_1.BaseService {
85
85
  static nextLogID = 0;
86
- version = "2.1.3";
86
+ version = "2.1.5";
87
87
  options;
88
88
  monitor;
89
89
  monitorIndexFile;
@@ -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<void>;
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
- createPool(): Promise<boolean>;
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
- await this.recreatePool();
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}", "Mysql server trying to create pool");
76
- this.serviceStarted = false;
77
- const ok = await this.createPool();
78
- if (!ok) {
79
- (0, LogService_1.logWarn)("${MysqlService.js}", "Mysql server not connected, retrying in 3 sec");
80
- if (this.timeoutID)
81
- clearTimeout(this.timeoutID);
82
- this.timeoutID = setTimeout(() => { this.recreatePool(); }, 3000);
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
- else {
85
- this.serviceStarted = true;
86
- (0, LogService_1.logInfo)("${MysqlService.js}", "Mysql Service started!");
87
- exports.S_MYSQL_STARTED.invoke();
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
- this.pool.getConnection((err, conn) => {
228
- if (err) {
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
- this.pool = mysql_1.default.createPool({
360
- connectionLimit: this.options.connectionLimit,
361
- host: this.options.host,
362
- user: this.options.user,
363
- password: this.options.password,
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
- (0, LogService_1.logCrit)("${MysqlService.js}", "Can't connect to MYSQL!");
371
- err = true;
427
+ return { err: this.createMysqlQueryError(e) };
372
428
  }
373
- if (!err && this.pool) {
374
- this.pool.on("error", (evt) => {
375
- (0, LogService_1.logError)("${MysqlService.js}", evt);
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",
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
- "mysql": "^2.18.1",
28
+ "mysql2": "^3.11.3",
29
29
  "ws": "^8.18.0"
30
30
  },
31
31
  "devDependencies": {