badmfck-api-server 2.9.3 → 2.9.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.
- package/dist/apiServer/DBService.d.ts +13 -0
- package/dist/apiServer/DBService.js +26 -2
- package/dist/apiServer/MysqlService.js +4 -1
- package/dist/apiServer/db/IDBAdapter.d.ts +2 -1
- package/dist/apiServer/db/MysqlAdapter.d.ts +5 -2
- package/dist/apiServer/db/MysqlAdapter.js +104 -71
- package/package.json +1 -1
@@ -21,6 +21,18 @@ export interface IDBQuery {
|
|
21
21
|
calculateCount?: boolean;
|
22
22
|
parseQueryOnly?: boolean;
|
23
23
|
}
|
24
|
+
export interface IDBBulkQuery {
|
25
|
+
dbid?: string;
|
26
|
+
bulk: {
|
27
|
+
query: string;
|
28
|
+
fields: {
|
29
|
+
[key: string]: IDBQueryField | null | string | number | boolean;
|
30
|
+
};
|
31
|
+
throwable?: boolean;
|
32
|
+
calculateCount?: boolean;
|
33
|
+
}[];
|
34
|
+
queued?: boolean;
|
35
|
+
}
|
24
36
|
export interface IDBError {
|
25
37
|
code: string;
|
26
38
|
errno: number;
|
@@ -52,6 +64,7 @@ export interface DBAdapterOptions {
|
|
52
64
|
debug?: boolean;
|
53
65
|
}
|
54
66
|
export declare const REQ_DB: Req<IDBQuery, IDBResult>;
|
67
|
+
export declare const REQ_DBX: Req<IDBBulkQuery, IDBResult[]>;
|
55
68
|
export declare class DBService extends BaseService {
|
56
69
|
static allInstances: DBService[];
|
57
70
|
options: IDBSericeOptions;
|
@@ -1,10 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.DBService = exports.REQ_DB = void 0;
|
3
|
+
exports.DBService = exports.REQ_DBX = exports.REQ_DB = void 0;
|
4
4
|
const badmfck_signal_1 = require("badmfck-signal");
|
5
5
|
const BaseService_1 = require("./BaseService");
|
6
6
|
const MysqlAdapter_1 = require("./db/MysqlAdapter");
|
7
|
-
exports.REQ_DB = new badmfck_signal_1.Req(undefined, "
|
7
|
+
exports.REQ_DB = new badmfck_signal_1.Req(undefined, "REQ_DB");
|
8
|
+
exports.REQ_DBX = new badmfck_signal_1.Req(undefined, "REQ_DBX");
|
8
9
|
class DBService extends BaseService_1.BaseService {
|
9
10
|
static allInstances = [];
|
10
11
|
options;
|
@@ -25,6 +26,29 @@ class DBService extends BaseService_1.BaseService {
|
|
25
26
|
if (this.options.type === "mysql") {
|
26
27
|
await this.createMysqlDatabase();
|
27
28
|
}
|
29
|
+
exports.REQ_DBX.listener = async (req) => {
|
30
|
+
if (!req.dbid && DBService.allInstances.length === 1 && DBService.allInstances[0].adapter)
|
31
|
+
return DBService.allInstances[0].adapter.bulk(req);
|
32
|
+
for (let i of DBService.allInstances) {
|
33
|
+
if (i.options.id === req.dbid && i.adapter)
|
34
|
+
return i.adapter.bulk(req);
|
35
|
+
}
|
36
|
+
const error = {
|
37
|
+
code: "DB_NOT_FOUND",
|
38
|
+
errno: -1,
|
39
|
+
fatal: true,
|
40
|
+
sql: "",
|
41
|
+
name: "DB_NOT_FOUND",
|
42
|
+
message: "DB not found: " + req.dbid
|
43
|
+
};
|
44
|
+
let result = [];
|
45
|
+
for (let i of req.bulk) {
|
46
|
+
result.push({ error: error });
|
47
|
+
if (i.throwable)
|
48
|
+
throw error;
|
49
|
+
}
|
50
|
+
return result;
|
51
|
+
};
|
28
52
|
exports.REQ_DB.listener = async (req) => {
|
29
53
|
if (!req.dbid && DBService.allInstances.length === 1 && DBService.allInstances[0].adapter)
|
30
54
|
return DBService.allInstances[0].adapter.query(req);
|
@@ -151,8 +151,11 @@ class MysqlService extends BaseService_1.BaseService {
|
|
151
151
|
const query = MysqlService.prepareQuery(i.query, i.fields);
|
152
152
|
promises.push(this.execute(query, i.rollbackQuery ?? null, i.transactionID ?? 0, i.throwable ?? false, i.calculateCount ?? false));
|
153
153
|
}
|
154
|
-
if (this.debug)
|
154
|
+
if (this.debug) {
|
155
155
|
console.log("Execute queries: ", data.length);
|
156
|
+
for (let i of data)
|
157
|
+
console.log(i);
|
158
|
+
}
|
156
159
|
const result = await Promise.all(promises);
|
157
160
|
for (let i of result) {
|
158
161
|
if (i.error && i.error.code === "CONN_ERR") {
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import { IDBQuery, IDBResult } from "../DBService";
|
1
|
+
import { IDBBulkQuery, IDBQuery, IDBResult } from "../DBService";
|
2
2
|
export interface IDBAdapter {
|
3
3
|
init(): Promise<void>;
|
4
4
|
finish(): Promise<void>;
|
5
5
|
prepareQuery(request: IDBQuery): string;
|
6
6
|
query(request: IDBQuery): Promise<IDBResult>;
|
7
|
+
bulk(request: IDBBulkQuery): Promise<IDBResult[]>;
|
7
8
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
import { DBAdapterOptions, IDBError, IDBQuery, IDBQueryField, IDBResult } from "../DBService";
|
2
|
+
import { DBAdapterOptions, IDBBulkQuery, IDBError, IDBQuery, IDBQueryField, IDBResult } from "../DBService";
|
3
3
|
import { IDBAdapter } from "./IDBAdapter";
|
4
4
|
import mysql from 'mysql2/promise';
|
5
5
|
import fs from 'fs';
|
@@ -34,7 +34,9 @@ export declare class MysqlAdapter implements IDBAdapter {
|
|
34
34
|
init(): Promise<void>;
|
35
35
|
setupTimers(): void;
|
36
36
|
recreatePool(): Promise<boolean>;
|
37
|
-
|
37
|
+
bulk(request: IDBBulkQuery): Promise<IDBResult[]>;
|
38
|
+
getConnection(transactionId?: number): Promise<mysql.PoolConnection | IDBError>;
|
39
|
+
query(request: IDBQuery, conn?: mysql.PoolConnection): Promise<IDBResult>;
|
38
40
|
finalizeConnection(conn: mysql.PoolConnection): void;
|
39
41
|
prepareQuery(request: IDBQuery): string;
|
40
42
|
static prepareQueryFieldValue(field: IDBQueryField): string | number | boolean | null | undefined;
|
@@ -44,5 +46,6 @@ export declare class MysqlAdapter implements IDBAdapter {
|
|
44
46
|
finish(): Promise<void>;
|
45
47
|
createMysqlQueryError(err: any, throwable?: boolean): IDBError;
|
46
48
|
storeTransactionAsProblem(trx: ITransaction, message: string): Promise<void>;
|
49
|
+
isError(obj: any): obj is IDBError;
|
47
50
|
}
|
48
51
|
export {};
|
@@ -20,9 +20,9 @@ class MysqlAdapter {
|
|
20
20
|
queries = [];
|
21
21
|
static nextTransactionID = 1;
|
22
22
|
transactions = [];
|
23
|
-
maxTransactionWaitTime = 1000 * 60 *
|
23
|
+
maxTransactionWaitTime = 1000 * 60 * 2;
|
24
24
|
lastSuccessQueryTime = 0;
|
25
|
-
pingInterval = 1000 * 60 *
|
25
|
+
pingInterval = 1000 * 60 * 5;
|
26
26
|
failReportFileStream = null;
|
27
27
|
failReportFileStreamName = null;
|
28
28
|
failReportLastAccessTime = 0;
|
@@ -79,8 +79,9 @@ class MysqlAdapter {
|
|
79
79
|
if (Date.now() - this.lastSuccessQueryTime > this.pingInterval) {
|
80
80
|
if (!this.pool)
|
81
81
|
return;
|
82
|
-
for (let i = 0; i < this.options.connectionLimit; i++)
|
82
|
+
for (let i = 0; i < this.options.connectionLimit; i++) {
|
83
83
|
this.query({ query: "SELECT 1 @NOLIMIT" });
|
84
|
+
}
|
84
85
|
}
|
85
86
|
}, 1000 * 30);
|
86
87
|
setInterval(() => {
|
@@ -153,103 +154,132 @@ class MysqlAdapter {
|
|
153
154
|
}
|
154
155
|
return true;
|
155
156
|
}
|
156
|
-
async
|
157
|
-
const
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
157
|
+
async bulk(request) {
|
158
|
+
const results = [];
|
159
|
+
let queries = [];
|
160
|
+
let conn = null;
|
161
|
+
if (request.queued) {
|
162
|
+
conn = await this.getConnection();
|
163
|
+
if (this.isError(conn)) {
|
164
|
+
for (let i of request.bulk)
|
165
|
+
results.push({ data: null, error: conn });
|
166
|
+
return results;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
for (let i of request.bulk) {
|
170
|
+
if (request.queued && conn) {
|
171
|
+
const response = await this.query({
|
172
|
+
query: i.query,
|
173
|
+
fields: i.fields,
|
174
|
+
throwable: i.throwable,
|
175
|
+
}, conn);
|
176
|
+
results.push(response);
|
177
|
+
continue;
|
178
|
+
}
|
179
|
+
queries.push(this.query({
|
180
|
+
query: i.query,
|
181
|
+
fields: i.fields,
|
182
|
+
throwable: i.throwable,
|
183
|
+
}));
|
184
|
+
}
|
185
|
+
if (conn) {
|
186
|
+
this.finalizeConnection(conn);
|
187
|
+
conn = null;
|
163
188
|
}
|
189
|
+
if (queries && queries.length > 0) {
|
190
|
+
const responses = await Promise.all(queries);
|
191
|
+
for (let i of responses)
|
192
|
+
results.push(i);
|
193
|
+
}
|
194
|
+
return results;
|
195
|
+
}
|
196
|
+
async getConnection(transactionId) {
|
164
197
|
if (!this.pool) {
|
165
198
|
(0, LogService_1.logError)("${MysqlAdapter.js}", "No pool created, can't execute query");
|
166
|
-
|
199
|
+
return {
|
167
200
|
code: "NO_POOL",
|
168
201
|
errno: 100000,
|
169
202
|
fatal: true,
|
170
|
-
sql:
|
203
|
+
sql: "",
|
171
204
|
name: "NO_POOL",
|
172
205
|
message: "Mysql pool not created",
|
173
206
|
};
|
174
|
-
if (request.throwable)
|
175
|
-
throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
|
176
|
-
return {
|
177
|
-
data: null,
|
178
|
-
error: error,
|
179
|
-
};
|
180
207
|
}
|
181
208
|
try {
|
182
209
|
let conn = null;
|
183
|
-
if (
|
184
|
-
conn = this.transactions.find(i => i.id ===
|
210
|
+
if (transactionId && transactionId > 0) {
|
211
|
+
conn = this.transactions.find(i => i.id === transactionId)?.conn ?? null;
|
185
212
|
if (this.options.debug)
|
186
213
|
console.log("Execute query on transaction: ", conn?.threadId);
|
187
214
|
}
|
188
215
|
else
|
189
216
|
conn = await this.pool.getConnection();
|
217
|
+
if (this.options.debug) {
|
218
|
+
console.log("Pool status: ", this.poolConnections, this.acquiredPoolConnections);
|
219
|
+
}
|
190
220
|
if (this.options.debug)
|
191
221
|
console.log("Execute query", conn?.threadId);
|
192
|
-
if (
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
this.finalizeConnection(conn);
|
223
|
-
else if (request.transactionID && request.throwable) {
|
224
|
-
this.rollbackTransaction(this.transactions.find(i => i.id === request.transactionID));
|
225
|
-
this.finalizeConnection(conn);
|
226
|
-
}
|
227
|
-
const error = this.createMysqlQueryError(e);
|
228
|
-
if (`${e}`.indexOf('ECONNREFUSED') !== -1)
|
229
|
-
this.recreatePool();
|
230
|
-
if (request.throwable)
|
231
|
-
throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
|
222
|
+
if (conn)
|
223
|
+
return conn;
|
224
|
+
}
|
225
|
+
catch (e) {
|
226
|
+
if (`${e}`.indexOf('ECONNREFUSED') !== -1)
|
227
|
+
this.recreatePool();
|
228
|
+
}
|
229
|
+
(0, LogService_1.logCrit)("${MysqlAdapter.js}", `No connection created!`);
|
230
|
+
return {
|
231
|
+
code: "NO_CONN",
|
232
|
+
errno: 100001,
|
233
|
+
fatal: true,
|
234
|
+
sql: "",
|
235
|
+
name: "NO_CONN",
|
236
|
+
message: "Mysql pool cant get connection",
|
237
|
+
};
|
238
|
+
}
|
239
|
+
async query(request, conn) {
|
240
|
+
const query = this.prepareQuery(request);
|
241
|
+
if (request.parseQueryOnly) {
|
242
|
+
return {
|
243
|
+
data: [{ query }],
|
244
|
+
error: null,
|
245
|
+
};
|
246
|
+
}
|
247
|
+
let doCloseConnection = false;
|
248
|
+
if (!conn) {
|
249
|
+
doCloseConnection = true;
|
250
|
+
conn = await this.getConnection(request.transactionID ?? -1);
|
251
|
+
if (this.isError(conn)) {
|
232
252
|
return {
|
233
253
|
data: null,
|
234
|
-
error:
|
254
|
+
error: conn,
|
235
255
|
};
|
236
256
|
}
|
237
257
|
}
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
message: e + "",
|
258
|
+
try {
|
259
|
+
const result = await conn.query(query);
|
260
|
+
this.lastSuccessQueryTime = +new Date();
|
261
|
+
if (!request.transactionID && doCloseConnection)
|
262
|
+
this.finalizeConnection(conn);
|
263
|
+
return {
|
264
|
+
data: result[0],
|
265
|
+
error: null
|
247
266
|
};
|
267
|
+
}
|
268
|
+
catch (e) {
|
269
|
+
if (!request.transactionID && doCloseConnection)
|
270
|
+
this.finalizeConnection(conn);
|
271
|
+
else if (request.transactionID && request.throwable) {
|
272
|
+
this.rollbackTransaction(this.transactions.find(i => i.id === request.transactionID));
|
273
|
+
this.finalizeConnection(conn);
|
274
|
+
}
|
275
|
+
const error = this.createMysqlQueryError(e);
|
276
|
+
if (`${e}`.indexOf('ECONNREFUSED') !== -1)
|
277
|
+
this.recreatePool();
|
248
278
|
if (request.throwable)
|
249
279
|
throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
|
250
280
|
return {
|
251
281
|
data: null,
|
252
|
-
error:
|
282
|
+
error: this.createMysqlQueryError(e),
|
253
283
|
};
|
254
284
|
}
|
255
285
|
}
|
@@ -462,6 +492,9 @@ class MysqlAdapter {
|
|
462
492
|
if (this.options.transactionFailReport)
|
463
493
|
this.options.transactionFailReport(trx, message);
|
464
494
|
}
|
495
|
+
isError(obj) {
|
496
|
+
return obj && "code" in obj && "errno" in obj && "name" in obj && "message" in obj;
|
497
|
+
}
|
465
498
|
}
|
466
499
|
exports.MysqlAdapter = MysqlAdapter;
|
467
500
|
const secret_key = "AKLWkajw%^&dgwqhw#98453i23bfk23rn2knknglrgjeit";
|