badmfck-api-server 2.2.1 → 2.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.
@@ -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",