badmfck-api-server 3.1.7 → 3.1.9
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/APIService.js +7 -45
- package/dist/apiServer/LogService.d.ts +1 -0
- package/dist/apiServer/LogService.js +21 -7
- package/dist/apiServer/db/MysqlAdapter.js +6 -6
- package/dist/apiServer/documentation/Documentation.js +1 -0
- package/dist/apiServer/monitor/Monitor.d.ts +7 -2
- package/dist/apiServer/monitor/Monitor.js +69 -15
- package/dist/apiServer/monitor/index.html +312 -5
- package/dist/apiServer/routes/Liveness.js +1 -0
- package/dist/apiServer/routes/Readiness.js +1 -0
- package/package.json +1 -1
@@ -36,8 +36,6 @@ const badmfck_signal_1 = require("badmfck-signal");
|
|
36
36
|
const LogService_1 = require("./LogService");
|
37
37
|
const Monitor_1 = require("./monitor/Monitor");
|
38
38
|
const path_1 = __importDefault(require("path"));
|
39
|
-
const crypto_1 = __importDefault(require("crypto"));
|
40
|
-
const fs_1 = __importDefault(require("fs"));
|
41
39
|
const express_fileupload_1 = __importDefault(require("express-fileupload"));
|
42
40
|
const os_1 = __importDefault(require("os"));
|
43
41
|
const Liveness_1 = require("./routes/Liveness");
|
@@ -97,7 +95,7 @@ async function Initializer(services) {
|
|
97
95
|
exports.Initializer = Initializer;
|
98
96
|
class APIService extends BaseService_1.BaseService {
|
99
97
|
static nextLogID = 0;
|
100
|
-
version = "3.1.
|
98
|
+
version = "3.1.9";
|
101
99
|
options;
|
102
100
|
monitor = null;
|
103
101
|
monitorIndexFile;
|
@@ -113,15 +111,14 @@ class APIService extends BaseService_1.BaseService {
|
|
113
111
|
const self = "http://localhost:" + this.options.port;
|
114
112
|
if (!this.options.corsHostWhiteList.find(val => val === self))
|
115
113
|
this.options.corsHostWhiteList.push();
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
this.monitor = new MonitorService_1.MonitorService();
|
120
|
-
this.monitor.init();
|
121
|
-
this.options.endpoints.push(new Monitor_1.Monitor());
|
122
|
-
}
|
114
|
+
exports.REQ_MONITOR_USERS.listener = async () => this.options.access.monitor ?? this.options.monitor ?? [];
|
115
|
+
exports.REQ_DOC_USERS.listener = async () => this.options.access.documentation ?? [];
|
116
|
+
this.options.endpoints.push(new Monitor_1.Monitor(this.options));
|
123
117
|
this.options.endpoints.push(new Documentation_1.Documentation(this.options));
|
124
118
|
this.options.endpoints.push(new ExternalServiceEndpoint_1.ExternalServiceEndpoint());
|
119
|
+
new DocumentService_1.DocumentGenerator(this.options.endpoints);
|
120
|
+
this.monitor = new MonitorService_1.MonitorService();
|
121
|
+
this.monitor.init();
|
125
122
|
this.options.endpoints.push(new Liveness_1.Liveness(this.started), new Readiness_1.Readiness(this.started));
|
126
123
|
exports.REQ_HTTP_REQUESTS_COUNT.listener = async () => this.requestsCount;
|
127
124
|
}
|
@@ -336,40 +333,6 @@ class APIService extends BaseService_1.BaseService {
|
|
336
333
|
}
|
337
334
|
app.use((req, res, next) => {
|
338
335
|
const tme = +new Date();
|
339
|
-
if (this.monitor && this.options && this.options.monitor) {
|
340
|
-
if (req.method === "GET") {
|
341
|
-
let monitorRequest = false;
|
342
|
-
for (let i of this.options.monitor) {
|
343
|
-
const hash = crypto_1.default.createHash("sha256").update(i.login + i.password).digest().toString("hex");
|
344
|
-
if (req.originalUrl.endsWith("/sm-" + hash)) {
|
345
|
-
monitorRequest = true;
|
346
|
-
break;
|
347
|
-
}
|
348
|
-
}
|
349
|
-
if (monitorRequest) {
|
350
|
-
const date = new Date();
|
351
|
-
try {
|
352
|
-
if (!this.monitorIndexFile)
|
353
|
-
this.monitorIndexFile = fs_1.default.readFileSync(path_1.default.resolve(__dirname, "monitor", "index.html"));
|
354
|
-
res.setHeader("Content-Type", "text/html");
|
355
|
-
res.setHeader("Content-Length", this.monitorIndexFile.byteLength);
|
356
|
-
res.status(200).send(this.monitorIndexFile);
|
357
|
-
}
|
358
|
-
catch (e) {
|
359
|
-
this.sendResponse(req.get("Referer") ?? "", res, {
|
360
|
-
error: {
|
361
|
-
code: 10002,
|
362
|
-
message: "Internal server error",
|
363
|
-
details: `${e}`
|
364
|
-
},
|
365
|
-
data: null,
|
366
|
-
httpStatus: 500
|
367
|
-
}, tme, req.path);
|
368
|
-
}
|
369
|
-
return;
|
370
|
-
}
|
371
|
-
}
|
372
|
-
}
|
373
336
|
this.sendResponse(req.get("Referer") ?? "", res, {
|
374
337
|
error: DefaultErrors_1.default.UNKNOWN_REQUEST,
|
375
338
|
data: null,
|
@@ -379,7 +342,6 @@ class APIService extends BaseService_1.BaseService {
|
|
379
342
|
server.listen(this.options.port, () => {
|
380
343
|
(0, LogService_1.logCrit)('${APIService.js}', 'API Service started at: ' + this.options.port + ", with base endpoint:" + this.options.baseEndPoint + ", ver.: " + this.version);
|
381
344
|
});
|
382
|
-
new DocumentService_1.DocumentGenerator(this.options.endpoints);
|
383
345
|
}
|
384
346
|
async sendResponse(ref, res, data, requestTime, endpoint, log, req) {
|
385
347
|
if (data.blockResponse) {
|
@@ -37,6 +37,7 @@ export declare const S_LOG: Signal<{
|
|
37
37
|
}>;
|
38
38
|
export declare const S_LOG_CREATED: Signal<ILogItem>;
|
39
39
|
export declare const S_LOG_CHANGE_LEVEL: Signal<LOG_LEVEL>;
|
40
|
+
export declare const REQ_CURRENT_LOG_LEVEL: Req<void, LOG_LEVEL>;
|
40
41
|
export declare const S_LOG_FLUSH: Signal<void>;
|
41
42
|
export declare const S_LOG_ADD_SERVICE_TO_WATCH: Signal<string>;
|
42
43
|
export declare const S_LOG_REMOVE_SERVICE_FROM_WATCH: Signal<string>;
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
23
23
|
return result;
|
24
24
|
};
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
-
exports.LogService = exports.REQ_LOG_UNIQUE_SERVICES = exports.REQ_LOG = exports.S_LOG_SET_TEXT_LIMIT = exports.S_LOG_REMOVE_SERVICE_FROM_WATCH = exports.S_LOG_ADD_SERVICE_TO_WATCH = exports.S_LOG_FLUSH = exports.S_LOG_CHANGE_LEVEL = exports.S_LOG_CREATED = exports.S_LOG = exports.logAPI = exports.logDB = exports.logError = exports.logCrit = exports.logWarn = exports.logInfo = exports.getDefaultLogOptions = exports.LOG_LEVEL = void 0;
|
26
|
+
exports.LogService = exports.REQ_LOG_UNIQUE_SERVICES = exports.REQ_LOG = exports.S_LOG_SET_TEXT_LIMIT = exports.S_LOG_REMOVE_SERVICE_FROM_WATCH = exports.S_LOG_ADD_SERVICE_TO_WATCH = exports.S_LOG_FLUSH = exports.REQ_CURRENT_LOG_LEVEL = exports.S_LOG_CHANGE_LEVEL = exports.S_LOG_CREATED = exports.S_LOG = exports.logAPI = exports.logDB = exports.logError = exports.logCrit = exports.logWarn = exports.logInfo = exports.getDefaultLogOptions = exports.LOG_LEVEL = void 0;
|
27
27
|
const badmfck_signal_1 = __importStar(require("badmfck-signal"));
|
28
28
|
const BaseService_1 = require("./BaseService");
|
29
29
|
var LOG_LEVEL;
|
@@ -44,21 +44,34 @@ const getDefaultLogOptions = () => {
|
|
44
44
|
};
|
45
45
|
};
|
46
46
|
exports.getDefaultLogOptions = getDefaultLogOptions;
|
47
|
-
const logInfo = (message, ...optional) => {
|
47
|
+
const logInfo = (message, ...optional) => {
|
48
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.INFO, data: [message, optional] });
|
49
|
+
};
|
48
50
|
exports.logInfo = logInfo;
|
49
|
-
const logWarn = (message, ...optional) => {
|
51
|
+
const logWarn = (message, ...optional) => {
|
52
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.WARN, data: [message, optional] });
|
53
|
+
};
|
50
54
|
exports.logWarn = logWarn;
|
51
|
-
const logCrit = (message, ...optional) => {
|
55
|
+
const logCrit = (message, ...optional) => {
|
56
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.CRIT, data: [message, optional] });
|
57
|
+
};
|
52
58
|
exports.logCrit = logCrit;
|
53
|
-
const logError = (message, ...optional) => {
|
59
|
+
const logError = (message, ...optional) => {
|
60
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.ERROR, data: [message, optional] });
|
61
|
+
};
|
54
62
|
exports.logError = logError;
|
55
|
-
const logDB = (message, ...optional) => {
|
63
|
+
const logDB = (message, ...optional) => {
|
64
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.DB, data: [message, optional] });
|
65
|
+
};
|
56
66
|
exports.logDB = logDB;
|
57
|
-
const logAPI = (message, ...optional) => {
|
67
|
+
const logAPI = (message, ...optional) => {
|
68
|
+
exports.S_LOG.invoke({ level: LOG_LEVEL.API, data: [message, optional] });
|
69
|
+
};
|
58
70
|
exports.logAPI = logAPI;
|
59
71
|
exports.S_LOG = new badmfck_signal_1.default();
|
60
72
|
exports.S_LOG_CREATED = new badmfck_signal_1.default();
|
61
73
|
exports.S_LOG_CHANGE_LEVEL = new badmfck_signal_1.default();
|
74
|
+
exports.REQ_CURRENT_LOG_LEVEL = new badmfck_signal_1.Req(undefined, "REQ_CURRENT_LOG_LEVEL");
|
62
75
|
exports.S_LOG_FLUSH = new badmfck_signal_1.default();
|
63
76
|
exports.S_LOG_ADD_SERVICE_TO_WATCH = new badmfck_signal_1.default();
|
64
77
|
exports.S_LOG_REMOVE_SERVICE_FROM_WATCH = new badmfck_signal_1.default();
|
@@ -120,6 +133,7 @@ class LogService extends BaseService_1.BaseService {
|
|
120
133
|
}
|
121
134
|
});
|
122
135
|
exports.S_LOG_CHANGE_LEVEL.subscribe(l => { this.level = l; });
|
136
|
+
exports.REQ_CURRENT_LOG_LEVEL.listener = async () => this.level;
|
123
137
|
exports.S_LOG_FLUSH.subscribe(() => this.log = []);
|
124
138
|
exports.S_LOG.subscribe((log) => {
|
125
139
|
if (log.level < this.level)
|
@@ -75,7 +75,7 @@ class MysqlAdapter {
|
|
75
75
|
}
|
76
76
|
this.transactions = this.transactions.filter(i => !removedIDs.includes(i.id));
|
77
77
|
if (this.options.debug && count - this.transactions.length > 0)
|
78
|
-
|
78
|
+
(0, LogService_1.logDB)("Removed: ", count - this.transactions.length);
|
79
79
|
if (Date.now() - this.lastSuccessQueryTime > this.pingInterval) {
|
80
80
|
if (!this.pool)
|
81
81
|
return;
|
@@ -191,7 +191,7 @@ class MysqlAdapter {
|
|
191
191
|
trxRequest.queries.push({ sql: "START TRANSACTION", status: "ok" });
|
192
192
|
this.transactions.push(trxRequest);
|
193
193
|
if (this.options.debug)
|
194
|
-
|
194
|
+
(0, LogService_1.logDB)("Transactions pool: ", this.transactions);
|
195
195
|
return { data: { transactionId: trxid } };
|
196
196
|
}
|
197
197
|
async tCommit(trxid) {
|
@@ -369,7 +369,7 @@ class MysqlAdapter {
|
|
369
369
|
conn.release();
|
370
370
|
conn.removeAllListeners();
|
371
371
|
if (this.options.debug)
|
372
|
-
|
372
|
+
(0, LogService_1.logDB)("Release connection: ", conn.threadId);
|
373
373
|
}
|
374
374
|
catch (e) {
|
375
375
|
(0, LogService_1.logCrit)("MysqlAdapter", `Can't release connection: ${e}`);
|
@@ -484,7 +484,7 @@ class MysqlAdapter {
|
|
484
484
|
async rollbackTransaction(trx, donNotRemove) {
|
485
485
|
let err = null;
|
486
486
|
try {
|
487
|
-
|
487
|
+
(0, LogService_1.logDB)("Rollback started", trx.conn.threadId);
|
488
488
|
await trx.conn.rollback();
|
489
489
|
await trx.conn.commit();
|
490
490
|
trx.conn.removeAllListeners();
|
@@ -492,7 +492,7 @@ class MysqlAdapter {
|
|
492
492
|
if (!donNotRemove)
|
493
493
|
this.transactions = this.transactions.filter(i => i.id !== trx.id);
|
494
494
|
if (this.options.debug)
|
495
|
-
|
495
|
+
(0, LogService_1.logDB)("Rollback complete", trx.conn.threadId);
|
496
496
|
}
|
497
497
|
catch (e) {
|
498
498
|
(0, LogService_1.logCrit)("MysqlAdapter", "Can't rollback transaction", trx.queries);
|
@@ -502,7 +502,7 @@ class MysqlAdapter {
|
|
502
502
|
return err;
|
503
503
|
}
|
504
504
|
async finish() {
|
505
|
-
|
505
|
+
(0, LogService_1.logInfo)("Finishing mysql service");
|
506
506
|
for (let i of this.transactions)
|
507
507
|
this.rollbackTransaction(i);
|
508
508
|
if (this.pool) {
|
@@ -18,6 +18,7 @@ class Documentation extends BaseEndpoint_1.BaseEndpoint {
|
|
18
18
|
super("doc");
|
19
19
|
this.apiServiceOptions = options;
|
20
20
|
this.ignoreInDocumentation = true;
|
21
|
+
this.ignoreHttpLogging = true;
|
21
22
|
this.registerEndpoints([{
|
22
23
|
ignoreInDocumentation: true,
|
23
24
|
endpoint: "json",
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { Signal } from "badmfck-signal";
|
2
|
+
import { APIServiceOptions } from "../APIService";
|
2
3
|
import { BaseEndpoint } from "../BaseEndpoint";
|
3
4
|
import { HTTPRequestVO, TransferPacketVO } from "../structures/Interfaces";
|
4
5
|
export interface IUserAction {
|
@@ -14,13 +15,17 @@ export declare const S_MONITOR_REGISTRATE_ACTION: Signal<IUserAction>;
|
|
14
15
|
export declare class Monitor extends BaseEndpoint {
|
15
16
|
ignoreHttpLogging: boolean;
|
16
17
|
ignoreInDocumentation: boolean;
|
18
|
+
indexHtmlFile: string | null;
|
19
|
+
apiServiceOptions: APIServiceOptions;
|
17
20
|
users: Map<string, IStatObject>;
|
18
|
-
constructor();
|
21
|
+
constructor(options: APIServiceOptions);
|
22
|
+
html(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
19
23
|
controllers(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
24
|
+
changeLogLevel(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
20
25
|
logs(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
21
26
|
netlog(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
22
27
|
metrics(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
23
28
|
serverStat(req: HTTPRequestVO): Promise<TransferPacketVO>;
|
24
|
-
checkAuthentication(req: HTTPRequestVO): Promise<
|
29
|
+
checkAuthentication(req: HTTPRequestVO): Promise<void>;
|
25
30
|
}
|
26
31
|
export {};
|
@@ -12,25 +12,81 @@ const crypto_1 = __importDefault(require("crypto"));
|
|
12
12
|
const os_1 = __importDefault(require("os"));
|
13
13
|
const DefaultErrors_1 = __importDefault(require("../structures/DefaultErrors"));
|
14
14
|
const MonitorService_1 = require("../MonitorService");
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
16
|
+
const path_1 = __importDefault(require("path"));
|
15
17
|
exports.S_MONITOR_REGISTRATE_ACTION = new badmfck_signal_1.Signal();
|
18
|
+
const logMap = {
|
19
|
+
ALL: 10,
|
20
|
+
API: 19,
|
21
|
+
INFO: 20,
|
22
|
+
DB: 25,
|
23
|
+
WARN: 30,
|
24
|
+
ERROR: 40,
|
25
|
+
CRIT: 50,
|
26
|
+
};
|
16
27
|
class Monitor extends BaseEndpoint_1.BaseEndpoint {
|
17
28
|
ignoreHttpLogging = true;
|
18
29
|
ignoreInDocumentation = true;
|
30
|
+
indexHtmlFile = null;
|
31
|
+
apiServiceOptions;
|
19
32
|
users = new Map();
|
20
|
-
constructor() {
|
21
|
-
super("
|
33
|
+
constructor(options) {
|
34
|
+
super("sm");
|
35
|
+
this.apiServiceOptions = options;
|
22
36
|
this.registerEndpoints([
|
37
|
+
{ ignoreInterceptor: true, endpoint: "html", handler: this.html },
|
23
38
|
{ ignoreInterceptor: true, endpoint: "log", handler: this.logs },
|
24
39
|
{ ignoreInterceptor: true, endpoint: "netlog", handler: this.netlog },
|
25
40
|
{ ignoreInterceptor: true, endpoint: "metrics", handler: this.metrics },
|
26
41
|
{ ignoreInterceptor: true, endpoint: "server", handler: this.serverStat },
|
27
|
-
{ ignoreInterceptor: true, endpoint: "controllers", handler: this.controllers }
|
42
|
+
{ ignoreInterceptor: true, endpoint: "controllers", handler: this.controllers },
|
43
|
+
{ ignoreInterceptor: true, endpoint: "changeLogLevel", handler: this.changeLogLevel, validationModel: {
|
44
|
+
level: Object.keys(logMap).join(",")
|
45
|
+
} }
|
28
46
|
]);
|
29
47
|
}
|
48
|
+
async html(req) {
|
49
|
+
if (!this.indexHtmlFile) {
|
50
|
+
this.indexHtmlFile = fs_1.default.readFileSync(path_1.default.resolve(__dirname, "index.html")).toString("utf-8");
|
51
|
+
let bend = this.apiServiceOptions.baseEndPoint;
|
52
|
+
if (!bend.endsWith("/"))
|
53
|
+
bend += "/";
|
54
|
+
let end = this.endpoint;
|
55
|
+
if (!end.endsWith("/"))
|
56
|
+
end += "/";
|
57
|
+
if (end.startsWith("/"))
|
58
|
+
end = end.substring(1);
|
59
|
+
const endpoint = bend + end + "json";
|
60
|
+
this.indexHtmlFile = this.indexHtmlFile.replace(/{{host}}/g, endpoint);
|
61
|
+
let projectName = this.apiServiceOptions.projectName;
|
62
|
+
if (!projectName)
|
63
|
+
projectName = "API Server";
|
64
|
+
projectName += " - Monitoring";
|
65
|
+
if (this.apiServiceOptions.appVersion)
|
66
|
+
projectName += " (v.:" + this.apiServiceOptions.appVersion + ")";
|
67
|
+
this.indexHtmlFile = this.indexHtmlFile.replace(/{{title}}/g, projectName);
|
68
|
+
}
|
69
|
+
return {
|
70
|
+
rawResponse: true,
|
71
|
+
data: this.indexHtmlFile,
|
72
|
+
headers: {
|
73
|
+
"Content-Type": "text/html",
|
74
|
+
"Content-Length": this.indexHtmlFile.length.toString()
|
75
|
+
}
|
76
|
+
};
|
77
|
+
}
|
30
78
|
async controllers(req) {
|
31
79
|
this.checkAuthentication(req);
|
32
80
|
return {};
|
33
81
|
}
|
82
|
+
async changeLogLevel(req) {
|
83
|
+
this.checkAuthentication(req);
|
84
|
+
const val = logMap[req.data.level];
|
85
|
+
if (!val)
|
86
|
+
throw { ...DefaultErrors_1.default.BAD_REQUEST, details: "bad log level" };
|
87
|
+
LogService_1.S_LOG_CHANGE_LEVEL.invoke(req.data.level);
|
88
|
+
return { data: (await LogService_1.REQ_CURRENT_LOG_LEVEL.request()) };
|
89
|
+
}
|
34
90
|
async logs(req) {
|
35
91
|
this.checkAuthentication(req);
|
36
92
|
const services = await LogService_1.REQ_LOG_UNIQUE_SERVICES.request();
|
@@ -65,23 +121,21 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
|
|
65
121
|
}
|
66
122
|
async checkAuthentication(req) {
|
67
123
|
const users = await APIService_1.REQ_MONITOR_USERS.request();
|
68
|
-
|
124
|
+
if (!users || users.length == 0)
|
125
|
+
throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "No users found for documentation access" };
|
126
|
+
let header = req.headers['authorization'];
|
69
127
|
if (!header)
|
70
128
|
throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "No authorization header found" };
|
129
|
+
header = header.split(" ").pop() ?? "";
|
130
|
+
if (!header || header.length < 32)
|
131
|
+
throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "Wrong authorization header" };
|
71
132
|
for (let i of users) {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
hashStr += JSON.stringify(req.method.toUpperCase());
|
76
|
-
hashStr += JSON.stringify(req.data ?? {});
|
77
|
-
hashStr += JSON.stringify(req.params ?? {});
|
78
|
-
let token = null;
|
79
|
-
token = "sha256 " + crypto_1.default.createHash('sha256').update(hashStr).digest('hex');
|
80
|
-
if (token == header) {
|
81
|
-
return true;
|
133
|
+
const hash = crypto_1.default.createHash("sha256").update(i.login + ":" + i.password).digest("hex");
|
134
|
+
if (hash === header) {
|
135
|
+
return;
|
82
136
|
}
|
83
137
|
}
|
84
|
-
throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "Invalid
|
138
|
+
throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "Invalid user" };
|
85
139
|
}
|
86
140
|
}
|
87
141
|
exports.Monitor = Monitor;
|