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.
@@ -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
|
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.
|
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.
|
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 (!
|
83
|
-
|
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.
|
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
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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.
|
285
|
+
const d = await conn.query(query);
|
286
|
+
income.push(d[0]);
|
247
287
|
}
|
248
288
|
catch (e) {
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
return { error:
|
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
|
-
|
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.
|
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
|
-
|
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({
|