badmfck-api-server 2.2.1 → 2.2.3

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.2.1";
86
+ version = "2.2.3";
87
87
  options;
88
88
  monitor;
89
89
  monitorIndexFile;
@@ -1,6 +1,8 @@
1
+ /// <reference types="node" />
1
2
  import { BaseService } from "./BaseService";
2
3
  import Signal, { Req } from "badmfck-signal";
3
4
  import * as mysql from "mysql2/promise";
5
+ import fs from "fs";
4
6
  export declare const S_MYSQL_STARTED: Signal<void>;
5
7
  export declare const REQ_MYSQL_QUERY: Req<MySqlQuery | MySqlQuery[], MysqlResult[]>;
6
8
  export declare const REQ_MYSQL_TRANSACTION: Req<MySqlQuery[], MysqlResult>;
@@ -9,7 +11,8 @@ export declare const REQ_MYSQL_TQUERY: Req<{
9
11
  query: MySqlQuery;
10
12
  tid: number;
11
13
  }, MysqlResult>;
12
- export declare const REQ_MYSQL_TEND: Req<number, MysqlError | null>;
14
+ export declare const REQ_MYSQL_TCOMMIT: Req<number, MysqlError | null>;
15
+ export declare const REQ_MYSQL_TROLLBACK: Req<number, MysqlError | null>;
13
16
  export declare const executeQuery: (query: MySqlQuery | MySqlQuery[]) => Promise<MysqlResult[]>;
14
17
  export interface MysqlServiceOptions {
15
18
  connectionLimit: number;
@@ -44,6 +47,7 @@ export interface MySqlQuery {
44
47
  query: string;
45
48
  fields: MysqlQueryField[] | MysqlQueryFieldObject;
46
49
  rollbackQuery?: string | null;
50
+ transactionID: number;
47
51
  }
48
52
  export interface MysqlQueryField {
49
53
  name: string;
@@ -82,6 +86,9 @@ export declare class MysqlService extends BaseService {
82
86
  static nextTransactionID: number;
83
87
  transactions: ITransaction[];
84
88
  maxTransactionWaitTime: number;
89
+ failReportFileStream: fs.WriteStream | null;
90
+ failReportFileStreamName: string | null;
91
+ failReportLastAccessTime: number;
85
92
  constructor(options: MysqlServiceOptions);
86
93
  static executeQuery(query: MySqlQuery | MySqlQuery[]): Promise<MysqlResult[]>;
87
94
  init(): Promise<void>;
@@ -93,7 +100,7 @@ export declare class MysqlService extends BaseService {
93
100
  static objectToFields(obj: MysqlQueryFieldObject | MysqlQueryField[]): MysqlQueryField[];
94
101
  static prepareQuery(query: string, fields: MysqlQueryField[] | MysqlQueryFieldObject): string;
95
102
  static prepareQueryFieldValue(value: string | number | boolean | null | undefined, system?: boolean): string | number | boolean | null | undefined;
96
- execute(query: string, rollbackQuery: string | null): Promise<MysqlResult>;
103
+ execute(query: string, rollbackQuery: string | null, transactionID: number): Promise<MysqlResult>;
97
104
  sendQuery(conn: mysql.PoolConnection, query: string, resolve: (data: MysqlResult) => void, rollback: string | null): Promise<void>;
98
105
  queryAsync(conn: mysql.PoolConnection, query: string): Promise<{
99
106
  err: MysqlError | null;
@@ -22,19 +22,25 @@ 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
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.MysqlService = exports.executeQuery = exports.REQ_MYSQL_TEND = exports.REQ_MYSQL_TQUERY = exports.REQ_MYSQL_TBEGIN = exports.REQ_MYSQL_TRANSACTION = exports.REQ_MYSQL_QUERY = exports.S_MYSQL_STARTED = void 0;
29
+ exports.MysqlService = exports.executeQuery = exports.REQ_MYSQL_TROLLBACK = exports.REQ_MYSQL_TCOMMIT = exports.REQ_MYSQL_TQUERY = exports.REQ_MYSQL_TBEGIN = exports.REQ_MYSQL_TRANSACTION = exports.REQ_MYSQL_QUERY = exports.S_MYSQL_STARTED = void 0;
27
30
  const BaseService_1 = require("./BaseService");
28
31
  const badmfck_signal_1 = __importStar(require("badmfck-signal"));
29
32
  const crypto_1 = require("crypto");
30
33
  const LogService_1 = require("./LogService");
31
34
  const mysql = __importStar(require("mysql2/promise"));
35
+ const fs_1 = __importDefault(require("fs"));
36
+ const path_1 = __importDefault(require("path"));
32
37
  exports.S_MYSQL_STARTED = new badmfck_signal_1.default();
33
38
  exports.REQ_MYSQL_QUERY = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_QUERY");
34
39
  exports.REQ_MYSQL_TRANSACTION = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TRANSACTION");
35
40
  exports.REQ_MYSQL_TBEGIN = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TRANSACTION_BEGING");
36
41
  exports.REQ_MYSQL_TQUERY = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TRANSACTION_ADD_OPERATION");
37
- exports.REQ_MYSQL_TEND = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TRANSACTION_END");
42
+ exports.REQ_MYSQL_TCOMMIT = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TCOMMIT");
43
+ exports.REQ_MYSQL_TROLLBACK = new badmfck_signal_1.Req(undefined, "REQ_MYSQL_TROLLBACK");
38
44
  const executeQuery = async (query) => { return await exports.REQ_MYSQL_QUERY.request(query); };
39
45
  exports.executeQuery = executeQuery;
40
46
  class MysqlService extends BaseService_1.BaseService {
@@ -48,6 +54,9 @@ class MysqlService extends BaseService_1.BaseService {
48
54
  static nextTransactionID = 0;
49
55
  transactions = [];
50
56
  maxTransactionWaitTime = 1000 * 60 * 2;
57
+ failReportFileStream = null;
58
+ failReportFileStreamName = null;
59
+ failReportLastAccessTime = 0;
51
60
  constructor(options) {
52
61
  super("mysql");
53
62
  this.options = options;
@@ -76,11 +85,18 @@ class MysqlService extends BaseService_1.BaseService {
76
85
  return false;
77
86
  });
78
87
  }, 1000 * 30);
88
+ setInterval(() => {
89
+ if (!this.failReportFileStream)
90
+ return;
91
+ if (Date.now() - this.failReportLastAccessTime > 1000 * 60 * 15) {
92
+ this.failReportFileStream.end();
93
+ this.failReportFileStream = null;
94
+ }
95
+ }, 1000 * 60 * 5);
79
96
  if (options.transactionFailReportDir) {
80
- const fs = require('fs');
81
97
  try {
82
- if (!fs.existsSync(options.transactionFailReportDir)) {
83
- fs.mkdirSync(options.transactionFailReportDir);
98
+ if (!fs_1.default.existsSync(options.transactionFailReportDir)) {
99
+ fs_1.default.mkdirSync(options.transactionFailReportDir);
84
100
  }
85
101
  }
86
102
  catch (e) {
@@ -118,7 +134,7 @@ class MysqlService extends BaseService_1.BaseService {
118
134
  const promises = [];
119
135
  for (let i of data) {
120
136
  const query = MysqlService.prepareQuery(i.query, i.fields);
121
- promises.push(this.execute(query, i.rollbackQuery ?? null));
137
+ promises.push(this.execute(query, i.rollbackQuery ?? null, i.transactionID));
122
138
  }
123
139
  return await Promise.all(promises);
124
140
  };
@@ -186,7 +202,30 @@ class MysqlService extends BaseService_1.BaseService {
186
202
  rollbackError: rollbackError
187
203
  };
188
204
  };
189
- exports.REQ_MYSQL_TEND.listener = async (tid) => {
205
+ exports.REQ_MYSQL_TROLLBACK.listener = async (tid) => {
206
+ const trx = this.transactions.find(i => i.id === tid);
207
+ if (!trx)
208
+ return {
209
+ code: "NO_TRX",
210
+ errno: 100004,
211
+ fatal: true,
212
+ sql: "",
213
+ name: "NO_TRX",
214
+ message: "Transaction not found"
215
+ };
216
+ this.transactions = this.transactions.filter(i => i.id !== tid);
217
+ try {
218
+ await trx.conn.rollback();
219
+ trx.conn.removeAllListeners();
220
+ trx.conn.release();
221
+ }
222
+ catch (e) {
223
+ (0, LogService_1.logError)("Can't rollback transaction");
224
+ return this.createMysqlQueryError(e);
225
+ }
226
+ return null;
227
+ };
228
+ exports.REQ_MYSQL_TCOMMIT.listener = async (tid) => {
190
229
  const trx = this.transactions.find(i => i.id === tid);
191
230
  if (!trx)
192
231
  return {
@@ -205,6 +244,14 @@ class MysqlService extends BaseService_1.BaseService {
205
244
  }
206
245
  catch (e) {
207
246
  this.storeTransactionAsProblem(trx, "Can't commit transaction");
247
+ try {
248
+ trx.conn.removeAllListeners();
249
+ await trx.conn.rollback();
250
+ trx.conn.release();
251
+ }
252
+ catch (e) {
253
+ (0, LogService_1.logError)("Can't rollback transaction");
254
+ }
208
255
  return this.createMysqlQueryError(e);
209
256
  }
210
257
  return null;
@@ -225,40 +272,46 @@ class MysqlService extends BaseService_1.BaseService {
225
272
  try {
226
273
  await conn.beginTransaction();
227
274
  await conn.query("SET autocommit=0");
228
- for (let i of data) {
229
- const query = MysqlService.prepareQuery(i.query, i.fields);
230
- let err = null;
231
- try {
232
- const d = await conn.query(query);
233
- income.push(d[0]);
234
- }
235
- catch (e) {
236
- err = this.createMysqlQueryError(e);
237
- }
238
- trx.queries.push({
239
- sql: query,
240
- status: err ? err.message : "completed"
241
- });
242
- if (err)
243
- return { error: err, data: null };
244
- }
275
+ }
276
+ catch (e) {
277
+ const err = this.createMysqlQueryError(e);
278
+ this.storeTransactionAsProblem(trx, err.message);
279
+ return { error: err, data: null };
280
+ }
281
+ for (let i of data) {
282
+ const query = MysqlService.prepareQuery(i.query, i.fields);
283
+ let err = null;
245
284
  try {
246
- await conn.commit();
285
+ const d = await conn.query(query);
286
+ income.push(d[0]);
247
287
  }
248
288
  catch (e) {
249
- let rollbackError = null;
250
- try {
251
- await conn.rollback();
252
- }
253
- catch (e2) {
254
- (0, LogService_1.logCrit)("${MysqlService.js}", "Can't rollback transaction!");
255
- rollbackError = this.createMysqlQueryError(e2);
256
- }
257
- return { error: this.createMysqlQueryError(e), data: null, rollbackError: rollbackError };
289
+ err = this.createMysqlQueryError(e);
290
+ }
291
+ trx.queries.push({
292
+ sql: query,
293
+ status: err ? err.message : "completed"
294
+ });
295
+ if (err) {
296
+ this.storeTransactionAsProblem(trx, err.message);
297
+ return { error: err, data: null };
258
298
  }
259
299
  }
300
+ try {
301
+ await conn.commit();
302
+ }
260
303
  catch (e) {
261
- return { error: this.createMysqlQueryError(e), data: null };
304
+ let rollbackError = null;
305
+ try {
306
+ await conn.rollback();
307
+ }
308
+ catch (e2) {
309
+ (0, LogService_1.logCrit)("${MysqlService.js}", "Can't rollback transaction!");
310
+ rollbackError = this.createMysqlQueryError(e2);
311
+ }
312
+ const err = this.createMysqlQueryError(e);
313
+ this.storeTransactionAsProblem(trx, err.message);
314
+ return { error: err, data: null, rollbackError: rollbackError };
262
315
  }
263
316
  return { error: null, data: income };
264
317
  };
@@ -283,13 +336,37 @@ class MysqlService extends BaseService_1.BaseService {
283
336
  (0, LogService_1.logCrit)("${MysqlService.js}", "Can't close MYSQL pool!");
284
337
  }
285
338
  }
339
+ if (this.failReportFileStream)
340
+ this.failReportFileStream.end();
341
+ this.failReportFileStream = null;
286
342
  }
287
343
  async storeTransactionAsProblem(trx, message) {
288
- if (!this.options.transactionFailReport) {
289
- (0, LogService_1.logCrit)("${MysqlService.js}", "Can't report failed transaction, no report function: transactionFailReport in options");
344
+ if (!this.options.transactionFailReport && !this.options.transactionFailReportDir) {
345
+ (0, LogService_1.logCrit)("${MysqlService.js}", "Can't report failed transaction, no report function: transactionFailReport in options, and transactionFailReportDir isnt set");
290
346
  return;
291
347
  }
292
- this.options.transactionFailReport(trx, message);
348
+ if (this.options.transactionFailReportDir) {
349
+ const yyymmdd = new Date().toISOString().substring(0, 10).replaceAll("-", "");
350
+ const date = new Date();
351
+ const file = path_1.default.resolve(this.options.transactionFailReportDir, yyymmdd + ".json");
352
+ if (this.failReportFileStream) {
353
+ if (this.failReportFileStreamName !== file) {
354
+ this.failReportFileStream.end();
355
+ this.failReportFileStream = null;
356
+ }
357
+ }
358
+ if (this.failReportFileStreamName) {
359
+ this.failReportFileStream = fs_1.default.createWriteStream(file, { flags: 'a' });
360
+ this.failReportFileStreamName = file;
361
+ }
362
+ this.failReportFileStream?.write(JSON.stringify({ trx, date, message }) + "\n{'s':'&$5__1AzZa'}\n", err => {
363
+ if (err)
364
+ (0, LogService_1.logCrit)("${MysqlService.js}", "Can't write to transaction fail report file");
365
+ });
366
+ this.failReportLastAccessTime = Date.now();
367
+ }
368
+ if (this.options.transactionFailReport)
369
+ this.options.transactionFailReport(trx, message);
293
370
  }
294
371
  async recreatePool() {
295
372
  (0, LogService_1.logInfo)("${MysqlService.js}", "Connecting to mysql: \n HOST: " + this.options.host + '\n PORT:' + this.options.port);
@@ -466,7 +543,7 @@ class MysqlService extends BaseService_1.BaseService {
466
543
  return "NULL";
467
544
  return value;
468
545
  }
469
- async execute(query, rollbackQuery) {
546
+ async execute(query, rollbackQuery, transactionID) {
470
547
  return new Promise(async (resolve, reject) => {
471
548
  if (!this.pool) {
472
549
  (0, LogService_1.logError)("${MysqlService.js}", "No pool");
@@ -484,7 +561,13 @@ class MysqlService extends BaseService_1.BaseService {
484
561
  return;
485
562
  }
486
563
  try {
487
- const conn = await this.pool.getConnection();
564
+ let conn = null;
565
+ if (transactionID && transactionID > 0) {
566
+ conn = this.transactions.find(i => i.id === transactionID)?.conn ?? null;
567
+ }
568
+ else {
569
+ conn = await this.pool.getConnection();
570
+ }
488
571
  if (!conn) {
489
572
  (0, LogService_1.logCrit)("${MysqlService.js}", `No connection created!`);
490
573
  resolve({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badmfck-api-server",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Simple API http server based on express",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",