badmfck-api-server 3.1.7 → 3.1.8
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 +2 -38
- 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 +68 -14
- package/dist/apiServer/monitor/index.html +312 -5
- 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.8";
|
101
99
|
options;
|
102
100
|
monitor = null;
|
103
101
|
monitorIndexFile;
|
@@ -118,7 +116,7 @@ class APIService extends BaseService_1.BaseService {
|
|
118
116
|
exports.REQ_DOC_USERS.listener = async () => this.options.access.documentation ?? [];
|
119
117
|
this.monitor = new MonitorService_1.MonitorService();
|
120
118
|
this.monitor.init();
|
121
|
-
this.options.endpoints.push(new Monitor_1.Monitor());
|
119
|
+
this.options.endpoints.push(new Monitor_1.Monitor(this.options));
|
122
120
|
}
|
123
121
|
this.options.endpoints.push(new Documentation_1.Documentation(this.options));
|
124
122
|
this.options.endpoints.push(new ExternalServiceEndpoint_1.ExternalServiceEndpoint());
|
@@ -336,40 +334,6 @@ class APIService extends BaseService_1.BaseService {
|
|
336
334
|
}
|
337
335
|
app.use((req, res, next) => {
|
338
336
|
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
337
|
this.sendResponse(req.get("Referer") ?? "", res, {
|
374
338
|
error: DefaultErrors_1.default.UNKNOWN_REQUEST,
|
375
339
|
data: null,
|
@@ -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() {
|
33
|
+
constructor(options) {
|
21
34
|
super("--sys-monitor");
|
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;
|