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.
@@ -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, "DB_SELECT");
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
- query(request: IDBQuery): Promise<IDBResult>;
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 * 1;
23
+ maxTransactionWaitTime = 1000 * 60 * 2;
24
24
  lastSuccessQueryTime = 0;
25
- pingInterval = 1000 * 60 * 2;
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 query(request) {
157
- const query = this.prepareQuery(request);
158
- if (request.parseQueryOnly) {
159
- return {
160
- data: [{ query }],
161
- error: null,
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
- const error = {
199
+ return {
167
200
  code: "NO_POOL",
168
201
  errno: 100000,
169
202
  fatal: true,
170
- sql: query,
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 (request.transactionID && request.transactionID > 0) {
184
- conn = this.transactions.find(i => i.id === request.transactionID)?.conn ?? null;
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 (!conn) {
193
- (0, LogService_1.logCrit)("${MysqlAdapter.js}", `No connection created!`);
194
- const error = {
195
- code: "NO_CONN",
196
- errno: 100001,
197
- fatal: true,
198
- sql: query,
199
- name: "NO_CONN",
200
- message: "Mysql pool cant get connection",
201
- };
202
- if (request.throwable)
203
- throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
204
- return {
205
- data: null,
206
- error: error,
207
- };
208
- }
209
- try {
210
- if (this.options.debug)
211
- (0, LogService_1.logInfo)("Execute query:", query);
212
- const result = await conn.query(query);
213
- if (!request.transactionID)
214
- this.finalizeConnection(conn);
215
- return {
216
- data: result[0],
217
- error: null
218
- };
219
- }
220
- catch (e) {
221
- if (!request.transactionID)
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: this.createMysqlQueryError(e),
254
+ error: conn,
235
255
  };
236
256
  }
237
257
  }
238
- catch (e) {
239
- (0, LogService_1.logCrit)("MysqlAdapter", `Error when executing query: ${query}`, e);
240
- const error = {
241
- code: "EXEC_ERROR",
242
- errno: 100002,
243
- fatal: true,
244
- sql: query,
245
- name: "EXECUTION_ERROR",
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: 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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badmfck-api-server",
3
- "version": "2.9.3",
3
+ "version": "2.9.5",
4
4
  "description": "Simple API http server based on express",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",