badmfck-api-server 2.1.1 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,6 +9,7 @@ export interface APIServiceNetworkLogItem {
9
9
  id: number;
10
10
  created: number;
11
11
  time: number;
12
+ referer?: string;
12
13
  request: {
13
14
  [key: string]: any;
14
15
  };
@@ -59,6 +60,6 @@ export declare class APIService extends BaseService {
59
60
  netLog: APIServiceNetworkLogItem[];
60
61
  constructor(options?: APIServiceOptions | null);
61
62
  init(): Promise<void>;
62
- sendResponse(res: Response, data: TransferPacketVO<any>, requestTime: number, endpoint?: string, log?: APIServiceNetworkLogItem | null, req?: HTTPRequestVO): Promise<void>;
63
+ sendResponse(ref: string, res: Response, data: TransferPacketVO<any>, requestTime: number, endpoint?: string, log?: APIServiceNetworkLogItem | null, req?: HTTPRequestVO): Promise<void>;
63
64
  checkDataLength(data: any, result?: any, lvl?: number): any;
64
65
  }
@@ -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.1.1";
86
+ version = "2.1.3";
87
87
  options;
88
88
  monitor;
89
89
  monitorIndexFile;
@@ -154,10 +154,10 @@ class APIService extends BaseService_1.BaseService {
154
154
  app.use(express_1.default.urlencoded({ limit: '10mb', extended: true }));
155
155
  app.use((0, express_fileupload_1.default)({
156
156
  limitHandler: (req, res, next) => {
157
- this.sendResponse(res, {
157
+ this.sendResponse(req.get("Referer") ?? "", res, {
158
158
  error: DefaultErrors_1.default.FILE_TOO_LARGE,
159
159
  data: null,
160
- httpStatus: 413
160
+ httpStatus: 413,
161
161
  }, +new Date(), req.path);
162
162
  },
163
163
  limits: { fileSize: this.options.fileLimit },
@@ -182,7 +182,7 @@ class APIService extends BaseService_1.BaseService {
182
182
  if (typeof err === "object" && err.status === 400 && 'body' in err && err.type === 'entity.parse.failed') {
183
183
  responseError = DefaultErrors_1.default.JSON_MALFORMED;
184
184
  }
185
- this.sendResponse(resp, {
185
+ this.sendResponse(req.get("Referer") ?? "", resp, {
186
186
  error: responseError,
187
187
  data: null,
188
188
  httpStatus: 400
@@ -231,7 +231,8 @@ class APIService extends BaseService_1.BaseService {
231
231
  params: req.params,
232
232
  headers: req.headers,
233
233
  endpoint: ep,
234
- files: req.files ?? null
234
+ files: req.files ?? null,
235
+ referer: req.get("Referer"),
235
236
  };
236
237
  if (this.options.preproducer) {
237
238
  try {
@@ -240,7 +241,7 @@ class APIService extends BaseService_1.BaseService {
240
241
  httpRequest.preproducerResult = preproducerResult;
241
242
  }
242
243
  catch (e) {
243
- this.sendResponse(res, { error: { code: 10002, message: "Internal server error", details: `${e}` }, data: null, httpStatus: 500 }, tme, ep, log, httpRequest);
244
+ this.sendResponse(req.get("Referer") ?? "", res, { error: { code: 10002, message: "Internal server error", details: `${e}` }, data: null, httpStatus: 500 }, tme, ep, log, httpRequest);
244
245
  return;
245
246
  }
246
247
  }
@@ -251,7 +252,7 @@ class APIService extends BaseService_1.BaseService {
251
252
  if (this.options.interceptor) {
252
253
  interceptorResult = await this.options.interceptor.execute(httpRequest);
253
254
  if (interceptorResult.error && !j.allowInterceptorError) {
254
- this.sendResponse(res, interceptorResult, tme, ep, log, httpRequest);
255
+ this.sendResponse(req.get("Referer") ?? "", res, interceptorResult, tme, ep, log, httpRequest);
255
256
  return;
256
257
  }
257
258
  httpRequest.interceptorResult = interceptorResult;
@@ -261,7 +262,7 @@ class APIService extends BaseService_1.BaseService {
261
262
  httpRequest.precheck = { data: this.options.monitor };
262
263
  const precheck = await i.precheck(httpRequest);
263
264
  if (precheck && precheck.error) {
264
- this.sendResponse(res, precheck, tme, ep, log, httpRequest);
265
+ this.sendResponse(req.get("Referer") ?? "", res, precheck, tme, ep, log, httpRequest);
265
266
  return;
266
267
  }
267
268
  httpRequest.precheck = precheck;
@@ -273,7 +274,7 @@ class APIService extends BaseService_1.BaseService {
273
274
  this.options.onError(e);
274
275
  if (this.monitor)
275
276
  this.monitor.registrateFatalError(ep);
276
- this.sendResponse(res, {
277
+ this.sendResponse(req.get("Referer") ?? "", res, {
277
278
  httpStatus: 500,
278
279
  error: {
279
280
  code: 10002,
@@ -283,7 +284,7 @@ class APIService extends BaseService_1.BaseService {
283
284
  }, tme, ep, log, httpRequest);
284
285
  return;
285
286
  }
286
- this.sendResponse(res, result, tme, ep, log, httpRequest);
287
+ this.sendResponse(req.get("Referer") ?? "", res, result, tme, ep, log, httpRequest);
287
288
  };
288
289
  execute();
289
290
  });
@@ -311,7 +312,7 @@ class APIService extends BaseService_1.BaseService {
311
312
  res.status(200).send(this.monitorIndexFile);
312
313
  }
313
314
  catch (e) {
314
- this.sendResponse(res, {
315
+ this.sendResponse(req.get("Referer") ?? "", res, {
315
316
  error: {
316
317
  code: 10002,
317
318
  message: "Internal server error",
@@ -325,7 +326,7 @@ class APIService extends BaseService_1.BaseService {
325
326
  }
326
327
  }
327
328
  }
328
- this.sendResponse(res, {
329
+ this.sendResponse(req.get("Referer") ?? "", res, {
329
330
  error: DefaultErrors_1.default.UNKNOWN_REQUEST,
330
331
  data: null,
331
332
  httpStatus: 404
@@ -335,7 +336,7 @@ class APIService extends BaseService_1.BaseService {
335
336
  (0, LogService_1.logCrit)('${APIService.js}', 'API Service started at: ' + this.options.port + ", with base endpoint:" + this.options.baseEndPoint + ", ver.: " + this.version);
336
337
  });
337
338
  }
338
- async sendResponse(res, data, requestTime, endpoint, log, req) {
339
+ async sendResponse(ref, res, data, requestTime, endpoint, log, req) {
339
340
  if (this.options.postproducer) {
340
341
  try {
341
342
  data = await this.options.postproducer(req, res, data, requestTime, endpoint, log);
@@ -351,8 +352,10 @@ class APIService extends BaseService_1.BaseService {
351
352
  data.endpoint = endpoint ?? "no_endpoint";
352
353
  if (this.options.appVersion)
353
354
  data.version = this.options.appVersion;
354
- if (log)
355
+ if (log) {
355
356
  log.time = data.responseTime;
357
+ log.referer = ref;
358
+ }
356
359
  if (this.monitor)
357
360
  this.monitor.registrateResponse(data.endpoint, data.responseTime);
358
361
  if (res.destroyed || res.closed) {
@@ -365,6 +368,24 @@ class APIService extends BaseService_1.BaseService {
365
368
  }
366
369
  else {
367
370
  try {
371
+ if (data.file) {
372
+ res.sendFile(data.file, err => {
373
+ if (err) {
374
+ if (log)
375
+ log.error = "Can't send file: " + data.file;
376
+ if (this.options.onError)
377
+ this.options.onError("Can't send file: " + data.file, err);
378
+ if (this.monitor && data.endpoint)
379
+ this.monitor.registrateAPIError(data.endpoint);
380
+ this.sendResponse(ref, res, {
381
+ error: DefaultErrors_1.default.CANT_SEND_FILE,
382
+ data: null,
383
+ httpStatus: 500
384
+ }, requestTime, data.endpoint);
385
+ }
386
+ });
387
+ return;
388
+ }
368
389
  if (data.redirect) {
369
390
  res.redirect(data.redirect);
370
391
  if (log)
@@ -18,6 +18,7 @@ export interface MysqlServiceOptions {
18
18
  }
19
19
  export interface MysqlResult {
20
20
  error?: MysqlError | null;
21
+ rollbackError?: MysqlError | null;
21
22
  isDuplicateError?: boolean;
22
23
  fields?: FieldInfo[] | null;
23
24
  data: any;
@@ -25,6 +26,7 @@ export interface MysqlResult {
25
26
  export interface MySqlQuery {
26
27
  query: string;
27
28
  fields: MysqlQueryField[] | MysqlQueryFieldObject;
29
+ rollbackQuery?: string | null;
28
30
  }
29
31
  export interface MysqlQueryField {
30
32
  name: string;
@@ -60,8 +62,13 @@ export declare class MysqlService extends BaseService {
60
62
  static objectToFields(obj: MysqlQueryFieldObject | MysqlQueryField[]): MysqlQueryField[];
61
63
  static prepareQuery(query: string, fields: MysqlQueryField[] | MysqlQueryFieldObject): string;
62
64
  static prepareQueryFieldValue(value: string | number | boolean | null | undefined, system?: boolean): string | number | boolean | null | undefined;
63
- execute(query: string): Promise<MysqlResult>;
64
- sendQuery(conn: PoolConnection, query: string, resolve: (data: MysqlResult) => void): void;
65
+ execute(query: string, rollbackQuery: string | null): Promise<MysqlResult>;
66
+ sendQuery(conn: PoolConnection, query: string, resolve: (data: MysqlResult) => void, rollback: string | null): Promise<void>;
67
+ queryAsync(conn: PoolConnection, query: string): Promise<{
68
+ err: MysqlError | null;
69
+ results?: any;
70
+ fields?: FieldInfo[];
71
+ }>;
65
72
  createPool(): Promise<boolean>;
66
73
  }
67
74
  export default MysqlService;
@@ -66,7 +66,7 @@ class MysqlService extends BaseService_1.BaseService {
66
66
  const promises = [];
67
67
  for (let i of data) {
68
68
  const query = MysqlService.prepareQuery(i.query, i.fields);
69
- promises.push(this.execute(query));
69
+ promises.push(this.execute(query, i.rollbackQuery ?? null));
70
70
  }
71
71
  return await Promise.all(promises);
72
72
  };
@@ -206,7 +206,7 @@ class MysqlService extends BaseService_1.BaseService {
206
206
  return "NULL";
207
207
  return value;
208
208
  }
209
- async execute(query) {
209
+ async execute(query, rollbackQuery) {
210
210
  return new Promise((resolve, reject) => {
211
211
  if (!this.pool) {
212
212
  (0, LogService_1.logError)("${MysqlService.js}", "No pool");
@@ -252,40 +252,23 @@ class MysqlService extends BaseService_1.BaseService {
252
252
  fields: null
253
253
  });
254
254
  }
255
- try {
256
- this.sendQuery(conn, query, resolve);
257
- }
258
- catch (e) {
259
- try {
260
- conn.removeAllListeners();
261
- conn.release();
262
- }
263
- catch (e) { }
264
- (0, LogService_1.logError)("${MysqlService.js}", "QUERY_ERR: " + e);
265
- resolve({
266
- error: {
267
- code: "QUERY_ERR",
268
- errno: 100002,
269
- fatal: true,
270
- sql: query,
271
- name: "QUERY_ERR",
272
- message: "Error: " + e
273
- },
274
- data: null,
275
- fields: null
276
- });
277
- }
255
+ this.sendQuery(conn, query, resolve, rollbackQuery);
278
256
  });
279
257
  });
280
258
  }
281
- sendQuery(conn, query, resolve) {
259
+ async sendQuery(conn, query, resolve, rollback) {
282
260
  let errCatched = false;
283
- conn.on("error", err => {
261
+ conn.on("error", async (err) => {
284
262
  errCatched = true;
285
- conn.release();
286
- conn.removeAllListeners();
287
- (0, LogService_1.logError)("${MysqlService.js}", err);
288
- conn.removeAllListeners();
263
+ let rollbackError = null;
264
+ if (rollback)
265
+ rollbackError = (await this.queryAsync(conn, rollback)).err;
266
+ (0, LogService_1.logError)("${MysqlService.js}->conn.on('error')", err);
267
+ try {
268
+ conn.release();
269
+ conn.removeAllListeners();
270
+ }
271
+ catch (e) { }
289
272
  resolve({
290
273
  error: {
291
274
  code: "CONN_ERR",
@@ -296,32 +279,65 @@ class MysqlService extends BaseService_1.BaseService {
296
279
  message: "Error: " + err
297
280
  },
298
281
  data: null,
299
- fields: null
282
+ fields: null,
283
+ rollbackError: rollbackError
300
284
  });
301
285
  });
302
286
  (0, LogService_1.logInfo)("${MysqlService.js}", query);
303
- conn.query(query, (err, results, fields) => {
287
+ const queryResult = await this.queryAsync(conn, query);
288
+ if (queryResult.err) {
289
+ let rollbackError = null;
290
+ if (rollback)
291
+ rollbackError = (await this.queryAsync(conn, rollback)).err;
292
+ try {
293
+ conn.release();
294
+ conn.removeAllListeners();
295
+ }
296
+ catch (e) { }
297
+ const dup = `${queryResult.err}`.toLowerCase().indexOf("er_dup_entry") !== -1;
298
+ (0, LogService_1.logError)("${MysqlService.js}->query error", queryResult.err);
299
+ resolve({
300
+ error: queryResult.err,
301
+ data: null,
302
+ fields: null,
303
+ rollbackError: rollbackError,
304
+ isDuplicateError: dup
305
+ });
306
+ }
307
+ try {
304
308
  conn.release();
305
309
  conn.removeAllListeners();
306
- if (errCatched)
307
- return;
308
- if (err) {
309
- const dup = `${err}`.toLowerCase().indexOf("er_dup_entry") !== -1;
310
- (0, LogService_1.logError)("${MysqlService.js}", err);
310
+ }
311
+ catch (e) { }
312
+ resolve({
313
+ error: queryResult.err,
314
+ data: queryResult.results,
315
+ fields: queryResult.fields
316
+ });
317
+ }
318
+ async queryAsync(conn, query) {
319
+ return new Promise((resolve, reject) => {
320
+ try {
321
+ conn.query(query, (err, results, fields) => {
322
+ resolve({
323
+ err: err,
324
+ results: results,
325
+ fields: fields
326
+ });
327
+ });
328
+ }
329
+ catch (e) {
311
330
  resolve({
312
- error: err,
313
- data: null,
314
- fields: null,
315
- isDuplicateError: dup
331
+ err: {
332
+ code: "QUERY_ERR",
333
+ errno: 100002,
334
+ fatal: true,
335
+ sql: query,
336
+ name: "QUERY_ERR",
337
+ message: "Error: " + e
338
+ }
316
339
  });
317
- return;
318
340
  }
319
- resolve({
320
- error: err,
321
- data: results,
322
- fields: fields
323
- });
324
- return;
325
341
  });
326
342
  }
327
343
  async createPool() {
@@ -4,6 +4,8 @@ declare class DefaultErrors {
4
4
  static UNKNOWN_REQUEST: IError;
5
5
  static JSON_MALFORMED: IError;
6
6
  static FILE_TOO_LARGE: IError;
7
+ static CANT_SEND_FILE: IError;
8
+ static FILE_NOT_EXISTS: IError;
7
9
  }
8
10
  export declare class ErrorUtils {
9
11
  static isError(obj: any): boolean;
@@ -7,6 +7,8 @@ class DefaultErrors {
7
7
  static UNKNOWN_REQUEST = { code: 2, message: "Unknown request" };
8
8
  static JSON_MALFORMED = { code: 3, message: "JSON malformed" };
9
9
  static FILE_TOO_LARGE = { code: 4, message: "File is too large" };
10
+ static CANT_SEND_FILE = { code: 5, message: "Can't send file" };
11
+ static FILE_NOT_EXISTS = { code: 5, message: "File not exists" };
10
12
  }
11
13
  class ErrorUtils {
12
14
  static isError(obj) {
@@ -12,6 +12,7 @@ export interface TransferPacketVO<T = any> {
12
12
  headers?: {
13
13
  [key: string]: string;
14
14
  };
15
+ file?: string;
15
16
  }
16
17
  export interface HTTPRequestVO<T = any> {
17
18
  raw: any;
@@ -28,6 +29,7 @@ export interface HTTPRequestVO<T = any> {
28
29
  preproducerResult?: any;
29
30
  precheck?: TransferPacketVO<any> | null;
30
31
  files: FileArray | null | undefined;
32
+ referer?: string;
31
33
  unlocked?: boolean;
32
34
  }
33
35
  export interface IError {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badmfck-api-server",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Simple API http server based on express",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",