miqro 7.2.7 → 7.2.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/build/esm/editor/auth.d.ts +6 -0
- package/build/esm/editor/auth.js +42 -0
- package/build/esm/editor/common/constants.d.ts +4 -0
- package/build/esm/editor/common/constants.js +20 -0
- package/build/esm/editor/common/constants.server.d.ts +2 -0
- package/build/esm/editor/common/constants.server.js +4 -0
- package/build/esm/editor/common/editor-index.d.ts +2 -0
- package/build/esm/editor/common/editor-index.js +14 -0
- package/build/esm/editor/common/html-encode.d.ts +1 -0
- package/build/esm/editor/common/html-encode.js +14 -0
- package/build/esm/editor/common/log-socket.d.ts +15 -0
- package/build/esm/editor/common/log-socket.js +71 -0
- package/build/esm/editor/common/templates.d.ts +11 -0
- package/build/esm/editor/common/templates.js +477 -0
- package/build/esm/editor/components/api-preview.d.ts +11 -0
- package/build/esm/editor/components/api-preview.js +92 -0
- package/build/esm/editor/components/editor.d.ts +16 -0
- package/build/esm/editor/components/editor.js +367 -0
- package/build/esm/editor/components/file-browser.d.ts +37 -0
- package/build/esm/editor/components/file-browser.js +127 -0
- package/build/esm/editor/components/file-editor-toolbar.d.ts +22 -0
- package/build/esm/editor/components/file-editor-toolbar.js +95 -0
- package/build/esm/editor/components/file-editor.d.ts +32 -0
- package/build/esm/editor/components/file-editor.js +61 -0
- package/build/esm/editor/components/filter-query.d.ts +1 -0
- package/build/esm/editor/components/filter-query.js +23 -0
- package/build/esm/editor/components/highlight-text-area.d.ts +11 -0
- package/build/esm/editor/components/highlight-text-area.js +127 -0
- package/build/esm/editor/components/log-viewer.d.ts +6 -0
- package/build/esm/editor/components/log-viewer.js +71 -0
- package/build/esm/editor/components/new-file.d.ts +10 -0
- package/build/esm/editor/components/new-file.js +119 -0
- package/build/esm/editor/components/scroll-query.d.ts +7 -0
- package/build/esm/editor/components/scroll-query.js +22 -0
- package/build/esm/editor/components/start-page.d.ts +13 -0
- package/build/esm/editor/components/start-page.js +32 -0
- package/build/esm/editor/http/admin/editor/api/fs/delete.api.d.ts +4 -0
- package/build/esm/editor/http/admin/editor/api/fs/delete.api.js +30 -0
- package/build/esm/editor/http/admin/editor/api/fs/read.api.d.ts +7 -0
- package/build/esm/editor/http/admin/editor/api/fs/read.api.js +50 -0
- package/build/esm/editor/http/admin/editor/api/fs/rename.api.d.ts +7 -0
- package/build/esm/editor/http/admin/editor/api/fs/rename.api.js +40 -0
- package/build/esm/editor/http/admin/editor/api/fs/scan.api.d.ts +26 -0
- package/build/esm/editor/http/admin/editor/api/fs/scan.api.js +150 -0
- package/build/esm/editor/http/admin/editor/api/fs/write.api.d.ts +3 -0
- package/build/esm/editor/http/admin/editor/api/fs/write.api.js +39 -0
- package/build/esm/editor/http/admin/editor/api/server/reload.api.d.ts +10 -0
- package/build/esm/editor/http/admin/editor/api/server/reload.api.js +46 -0
- package/build/esm/editor/http/admin/editor/api/server/restart.api.d.ts +10 -0
- package/build/esm/editor/http/admin/editor/api/server/restart.api.js +46 -0
- package/build/esm/editor/http/admin/editor/editor.d.ts +1 -0
- package/build/esm/editor/http/admin/editor/editor.js +8 -0
- package/build/esm/editor/http/admin/editor/index.api.d.ts +3 -0
- package/build/esm/editor/http/admin/editor/index.api.js +23 -0
- package/build/esm/editor/server.d.ts +3 -0
- package/build/esm/editor/server.js +49 -0
- package/build/esm/editor/ws.d.ts +3 -0
- package/build/esm/editor/ws.js +12 -0
- package/build/esm/src/common/admin-interface.d.ts +36 -0
- package/build/esm/src/common/admin-interface.js +44 -0
- package/build/esm/src/common/exit.js +18 -2
- package/build/esm/src/common/watch.js +8 -3
- package/build/esm/src/services/app.d.ts +1 -1
- package/build/esm/src/services/editor.d.ts +1 -1
- package/build/esm/src/services/utils/admin-interface.d.ts +1 -1
- package/build/esm/src/services/utils/websocketmanager.d.ts +1 -1
- package/build/lib.cjs +48 -20
- package/editor/auth.ts +52 -0
- package/editor/common/constants.server.ts +5 -0
- package/editor/common/constants.ts +21 -0
- package/editor/common/editor-index.tsx +17 -0
- package/editor/common/html-encode.ts +14 -0
- package/editor/common/log-socket.tsx +87 -0
- package/editor/common/templates.ts +481 -0
- package/editor/components/api-preview.tsx +118 -0
- package/editor/components/editor.tsx +496 -0
- package/editor/components/file-browser.tsx +311 -0
- package/editor/components/file-editor-toolbar.tsx +194 -0
- package/editor/components/file-editor.tsx +125 -0
- package/editor/components/filter-query.tsx +26 -0
- package/editor/components/highlight-text-area.tsx +148 -0
- package/editor/components/log-viewer.tsx +113 -0
- package/editor/components/new-file.tsx +172 -0
- package/editor/components/scroll-query.tsx +25 -0
- package/editor/components/start-page.tsx +52 -0
- package/editor/http/admin/editor/api/fs/delete.api.tsx +32 -0
- package/editor/http/admin/editor/api/fs/read.api.tsx +55 -0
- package/editor/http/admin/editor/api/fs/rename.api.tsx +41 -0
- package/editor/http/admin/editor/api/fs/scan.api.tsx +181 -0
- package/editor/http/admin/editor/api/fs/write.api.tsx +41 -0
- package/editor/http/admin/editor/api/server/reload.api.ts +53 -0
- package/editor/http/admin/editor/api/server/restart.api.tsx +52 -0
- package/editor/http/admin/editor/editor.tsx +10 -0
- package/editor/http/admin/editor/index.api.tsx +43 -0
- package/editor/server.ts +57 -0
- package/editor/ws.ts +17 -0
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { Logger } from "@miqro/core";
|
|
|
2
2
|
import { ClusterWebSocketServer2 } from "./cluster-ws.js";
|
|
3
3
|
import { WSConfig } from "../../types.js";
|
|
4
4
|
import { LogProvider } from "./log.js";
|
|
5
|
-
import { EditorAdminInterface } from "
|
|
5
|
+
import { EditorAdminInterface } from "../../common/admin-interface.js";
|
|
6
6
|
export interface WebSocketManagerOptions {
|
|
7
7
|
logger?: Logger | Console;
|
|
8
8
|
loggerProvider?: LogProvider;
|
package/build/lib.cjs
CHANGED
|
@@ -2591,7 +2591,7 @@ var init_app = __esm({
|
|
|
2591
2591
|
});
|
|
2592
2592
|
});
|
|
2593
2593
|
if (config?.onUpgrade) {
|
|
2594
|
-
this.httpServer.on("upgrade", (req, socket, head) => {
|
|
2594
|
+
this.httpServer.on("upgrade", async (req, socket, head) => {
|
|
2595
2595
|
try {
|
|
2596
2596
|
const logger = loggerFactory(req.uuid, req);
|
|
2597
2597
|
try {
|
|
@@ -2600,7 +2600,8 @@ var init_app = __esm({
|
|
|
2600
2600
|
socket.destroy();
|
|
2601
2601
|
} else {
|
|
2602
2602
|
if (config?.onUpgrade) {
|
|
2603
|
-
|
|
2603
|
+
const ret = await config.onUpgrade(req, socket, head);
|
|
2604
|
+
return ret;
|
|
2604
2605
|
} else {
|
|
2605
2606
|
socket.end("HTTP/1.1 400 Bad Request");
|
|
2606
2607
|
socket.destroy();
|
|
@@ -2679,7 +2680,7 @@ Sec-WebSocket-Accept: ${acceptValue}${extra}\r
|
|
|
2679
2680
|
\r
|
|
2680
2681
|
`;
|
|
2681
2682
|
}
|
|
2682
|
-
function parseFrame(buffer) {
|
|
2683
|
+
function parseFrame(buffer, maxFrameSize = DEFAULT_MAX_FRAME_SIZE) {
|
|
2683
2684
|
const firstByte = buffer.readUInt8(0);
|
|
2684
2685
|
const opCode = firstByte & 15;
|
|
2685
2686
|
if (opCode === OPCODES.close) {
|
|
@@ -2699,6 +2700,9 @@ function parseFrame(buffer) {
|
|
|
2699
2700
|
payloadLength = Number(buffer.readBigUInt64BE(offset));
|
|
2700
2701
|
offset += 8;
|
|
2701
2702
|
}
|
|
2703
|
+
if (payloadLength > maxFrameSize) {
|
|
2704
|
+
return null;
|
|
2705
|
+
}
|
|
2702
2706
|
const isMasked = Boolean(secondByte >>> 7 & 1);
|
|
2703
2707
|
if (isMasked) {
|
|
2704
2708
|
const maskingKey = buffer.readUInt32BE(offset);
|
|
@@ -2742,7 +2746,7 @@ function createFrame(payload) {
|
|
|
2742
2746
|
buffer.write(payload, payloadBytesOffset);
|
|
2743
2747
|
return buffer;
|
|
2744
2748
|
}
|
|
2745
|
-
var import_crypto3, WebSocketServer, PING, OPCODES, GUID;
|
|
2749
|
+
var import_crypto3, WebSocketServer, PING, OPCODES, GUID, DEFAULT_MAX_FRAME_SIZE;
|
|
2746
2750
|
var init_websocket = __esm({
|
|
2747
2751
|
"node_modules/@miqro/core/build/websocket.js"() {
|
|
2748
2752
|
import_crypto3 = require("crypto");
|
|
@@ -2776,12 +2780,21 @@ var init_websocket = __esm({
|
|
|
2776
2780
|
if (!client) {
|
|
2777
2781
|
throw new Error("client not found");
|
|
2778
2782
|
}
|
|
2783
|
+
if (!client.socket.writable) {
|
|
2784
|
+
this.clients.delete(clientUUID);
|
|
2785
|
+
throw new Error("socket not writable");
|
|
2786
|
+
}
|
|
2787
|
+
if (client.socket.writableLength > (this.options.maxFrameSize ?? DEFAULT_MAX_FRAME_SIZE)) {
|
|
2788
|
+
client.socket.destroy();
|
|
2789
|
+
this.clients.delete(clientUUID);
|
|
2790
|
+
throw new Error("client send buffer full");
|
|
2791
|
+
}
|
|
2779
2792
|
return new Promise((resolve24, reject) => {
|
|
2780
2793
|
try {
|
|
2781
|
-
client.
|
|
2794
|
+
client.socket.write(createFrame(data), (err) => {
|
|
2782
2795
|
if (err) {
|
|
2783
2796
|
try {
|
|
2784
|
-
client.
|
|
2797
|
+
client.socket.destroy(err);
|
|
2785
2798
|
} catch (e) {
|
|
2786
2799
|
console.error(e);
|
|
2787
2800
|
}
|
|
@@ -2793,7 +2806,7 @@ var init_websocket = __esm({
|
|
|
2793
2806
|
});
|
|
2794
2807
|
} catch (e) {
|
|
2795
2808
|
try {
|
|
2796
|
-
client.
|
|
2809
|
+
client.socket.destroy();
|
|
2797
2810
|
} catch (e2) {
|
|
2798
2811
|
console.error(e2);
|
|
2799
2812
|
}
|
|
@@ -2840,8 +2853,8 @@ var init_websocket = __esm({
|
|
|
2840
2853
|
};
|
|
2841
2854
|
req.logger.debug("upgrading connection");
|
|
2842
2855
|
socket.write(createUpgradeHeaders(acceptKey, extraHeaders));
|
|
2843
|
-
socket.on("data", (data) => {
|
|
2844
|
-
const frame = parseFrame(data);
|
|
2856
|
+
socket.on("data", async (data) => {
|
|
2857
|
+
const frame = parseFrame(data, this.options.maxFrameSize);
|
|
2845
2858
|
if (frame === PING) {
|
|
2846
2859
|
try {
|
|
2847
2860
|
socket.write(Buffer.from([138, 0]));
|
|
@@ -2854,7 +2867,7 @@ var init_websocket = __esm({
|
|
|
2854
2867
|
socket.destroy();
|
|
2855
2868
|
} else {
|
|
2856
2869
|
try {
|
|
2857
|
-
this.options.onMessage(client, frame);
|
|
2870
|
+
await this.options.onMessage(client, frame);
|
|
2858
2871
|
} catch (e) {
|
|
2859
2872
|
req.logger.error(e);
|
|
2860
2873
|
}
|
|
@@ -2869,23 +2882,23 @@ var init_websocket = __esm({
|
|
|
2869
2882
|
socket.destroy();
|
|
2870
2883
|
}
|
|
2871
2884
|
});
|
|
2872
|
-
socket.on("error", (error2) => {
|
|
2885
|
+
socket.on("error", async (error2) => {
|
|
2873
2886
|
req.logger.debug("upgraded connection error!");
|
|
2874
2887
|
req.logger.error(error2);
|
|
2875
2888
|
if (this.options.onError) {
|
|
2876
2889
|
try {
|
|
2877
|
-
this.options.onError(client, error2);
|
|
2890
|
+
await this.options.onError(client, error2);
|
|
2878
2891
|
} catch (e) {
|
|
2879
2892
|
req.logger.error(e);
|
|
2880
2893
|
}
|
|
2881
2894
|
}
|
|
2882
2895
|
});
|
|
2883
|
-
socket.on("end", () => {
|
|
2896
|
+
socket.on("end", async () => {
|
|
2884
2897
|
req.logger.debug("upgraded connection disconnected!");
|
|
2885
2898
|
this.clients.delete(uuid);
|
|
2886
2899
|
if (this.options.onDisconnect) {
|
|
2887
2900
|
try {
|
|
2888
|
-
this.options.onDisconnect(client);
|
|
2901
|
+
await this.options.onDisconnect(client);
|
|
2889
2902
|
} catch (e) {
|
|
2890
2903
|
req.logger.error(e);
|
|
2891
2904
|
}
|
|
@@ -2895,7 +2908,7 @@ var init_websocket = __esm({
|
|
|
2895
2908
|
this.clients.set(uuid, client);
|
|
2896
2909
|
if (this.options.onConnection) {
|
|
2897
2910
|
try {
|
|
2898
|
-
this.options.onConnection(client);
|
|
2911
|
+
await this.options.onConnection(client);
|
|
2899
2912
|
} catch (e) {
|
|
2900
2913
|
req.logger.error(e);
|
|
2901
2914
|
}
|
|
@@ -2908,6 +2921,7 @@ var init_websocket = __esm({
|
|
|
2908
2921
|
PING = /* @__PURE__ */ Symbol();
|
|
2909
2922
|
OPCODES = { text: 1, close: 8, ping: 9, pong: 10 };
|
|
2910
2923
|
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
2924
|
+
DEFAULT_MAX_FRAME_SIZE = 1024 * 1024;
|
|
2911
2925
|
}
|
|
2912
2926
|
});
|
|
2913
2927
|
|
|
@@ -14229,9 +14243,13 @@ async function watchAndServer(app) {
|
|
|
14229
14243
|
try {
|
|
14230
14244
|
stopWatch();
|
|
14231
14245
|
setTimeout(async () => {
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14246
|
+
try {
|
|
14247
|
+
watchLogger?.debug("closed");
|
|
14248
|
+
await app.reload();
|
|
14249
|
+
reWatch();
|
|
14250
|
+
} catch (e) {
|
|
14251
|
+
watchLogger?.error(e);
|
|
14252
|
+
}
|
|
14235
14253
|
}, 500);
|
|
14236
14254
|
} catch (e) {
|
|
14237
14255
|
watchLogger?.error(e);
|
|
@@ -14306,11 +14324,11 @@ function setupExitHandlers(app) {
|
|
|
14306
14324
|
exceptionOccured = true;
|
|
14307
14325
|
cleanJSX(app);
|
|
14308
14326
|
if (app.server) {
|
|
14309
|
-
app.stop();
|
|
14327
|
+
await app.stop();
|
|
14310
14328
|
}
|
|
14311
14329
|
process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
|
|
14312
14330
|
});
|
|
14313
|
-
process.on("exit",
|
|
14331
|
+
process.on("exit", function(code) {
|
|
14314
14332
|
if (exceptionOccured) {
|
|
14315
14333
|
app.logger?.error("Exception occured");
|
|
14316
14334
|
} else {
|
|
@@ -14320,6 +14338,16 @@ function setupExitHandlers(app) {
|
|
|
14320
14338
|
}
|
|
14321
14339
|
}
|
|
14322
14340
|
});
|
|
14341
|
+
process.on("unhandledRejection", async (reason) => {
|
|
14342
|
+
app.logger?.error("Unhandled rejection:");
|
|
14343
|
+
app.logger?.error(reason);
|
|
14344
|
+
exceptionOccured = true;
|
|
14345
|
+
cleanJSX(app);
|
|
14346
|
+
if (app.server) {
|
|
14347
|
+
await app.stop();
|
|
14348
|
+
}
|
|
14349
|
+
process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
|
|
14350
|
+
});
|
|
14323
14351
|
process.on("SIGTERM", function() {
|
|
14324
14352
|
app.logger?.info("SIGTERM received");
|
|
14325
14353
|
process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
|
package/editor/auth.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { AuthConfig, ServerRequest } from "../src/types.js";
|
|
3
|
+
import { AdminRequest } from "../src/common/admin-interface.js";
|
|
4
|
+
|
|
5
|
+
export const ADMIN_EDITOR_AUTH_KEY = "$$ADMIN_EDITOR_AUTH_KEY$$";
|
|
6
|
+
|
|
7
|
+
export const ADMIN_EDITOR_AUTH_QUERY = "key";
|
|
8
|
+
export const ADMIN_EDITOR_AUTH_COOKIE = ADMIN_EDITOR_AUTH_KEY;
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
authService: {
|
|
12
|
+
verify: async (args) => {
|
|
13
|
+
|
|
14
|
+
const adminInterface = (args.req as AdminRequest).editor;
|
|
15
|
+
const serverInterface = (args.req as any as ServerRequest).server;
|
|
16
|
+
const KEY = (adminInterface ? adminInterface.getCache() : serverInterface.cache).get<string>(ADMIN_EDITOR_AUTH_KEY);
|
|
17
|
+
|
|
18
|
+
const validSesson = {
|
|
19
|
+
username: "username",
|
|
20
|
+
account: "account",
|
|
21
|
+
groups: [],
|
|
22
|
+
token: args.token
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const queryToken = args.req.query[ADMIN_EDITOR_AUTH_QUERY];
|
|
26
|
+
const cookieToken = args.req.cookies[ADMIN_EDITOR_AUTH_COOKIE];
|
|
27
|
+
|
|
28
|
+
//console.log("\n\nqueryToken[%s] cookieToken[%s] KEY[%s]\n\n", queryToken, cookieToken, KEY);
|
|
29
|
+
|
|
30
|
+
if (queryToken) {
|
|
31
|
+
if (typeof queryToken === "string" && timingSafeEqual(Buffer.from(queryToken), Buffer.from(KEY))) {
|
|
32
|
+
args.res.setCookie(ADMIN_EDITOR_AUTH_COOKIE, KEY, {
|
|
33
|
+
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 31 * 12 * 500),
|
|
34
|
+
httpOnly: true,
|
|
35
|
+
|
|
36
|
+
//secure: true,
|
|
37
|
+
path: "/",
|
|
38
|
+
//sameSite: "strict"
|
|
39
|
+
});
|
|
40
|
+
args.req.searchParams.delete(ADMIN_EDITOR_AUTH_QUERY);
|
|
41
|
+
const queryString = args.req.searchParams.toString();
|
|
42
|
+
const redirect = args.req.path + (queryString ? "?" + queryString : "");
|
|
43
|
+
await args.res.redirect(redirect);
|
|
44
|
+
return validSesson;
|
|
45
|
+
}
|
|
46
|
+
} else if (cookieToken) {
|
|
47
|
+
return cookieToken === KEY ? validSesson : null;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
} as AuthConfig;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const BASEEDITOR_PATH = "/admin/editor";
|
|
2
|
+
export const LOG_SOCKET_PATH = "/admin/socket";
|
|
3
|
+
export const LOG_WRITE_EVENT = "LogWrite";
|
|
4
|
+
|
|
5
|
+
export const SUPPORTED_LANGUAGES = [
|
|
6
|
+
"text",
|
|
7
|
+
"json",
|
|
8
|
+
"javascript",
|
|
9
|
+
"typescript",
|
|
10
|
+
"dockerfile",
|
|
11
|
+
"yaml",
|
|
12
|
+
"xml",
|
|
13
|
+
"html",
|
|
14
|
+
"css",
|
|
15
|
+
"scss",
|
|
16
|
+
"markdown",
|
|
17
|
+
"c",
|
|
18
|
+
"cpp",
|
|
19
|
+
"bash",
|
|
20
|
+
"python"
|
|
21
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { scanDir } from "../http/admin/editor/api/fs/scan.api.js";
|
|
2
|
+
import { parseInflateErrors } from "../http/admin/editor/api/server/restart.api.js";
|
|
3
|
+
import { AdminRequest } from "../../src/common/admin-interface.js";
|
|
4
|
+
import { HTMLEncode } from "./html-encode.js";
|
|
5
|
+
|
|
6
|
+
export function EditorIndex(editorCSS: string, editorJS: string, enableHotReload: boolean) {
|
|
7
|
+
return async function editorIndex(req: AdminRequest, res) {
|
|
8
|
+
const admin = req.editor;
|
|
9
|
+
|
|
10
|
+
const errors = parseInflateErrors(admin ? admin.getInflateErrors() : []);
|
|
11
|
+
const files = scanDir(req);
|
|
12
|
+
const migrations = admin ? admin.getMigrations().map(m => m.name) : [];
|
|
13
|
+
const services = admin ? admin.getServices() : ["."];
|
|
14
|
+
const hotReload = enableHotReload ? (admin ? admin.getHotReloadHTML() : "") : "";
|
|
15
|
+
res.html(`<!DOCTYPE html><html><body><style>${editorCSS}</style><script type="module">${editorJS}</script><editor-component class="main-container" reloadstring="${req.uuid}" migrations="${HTMLEncode(JSON.stringify(migrations))}" services="${HTMLEncode(JSON.stringify(services))}" errors="${HTMLEncode(JSON.stringify(errors))}" files="${HTMLEncode(JSON.stringify(files))}"><noscript>Enable JavaScript</noscript></editor-component>${hotReload}</body></html>`)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function HTMLEncode(str: string): string {
|
|
2
|
+
let i = str.length;
|
|
3
|
+
const aRet: string[] = [];
|
|
4
|
+
|
|
5
|
+
while (i--) {
|
|
6
|
+
const iC = str[i].charCodeAt(0);
|
|
7
|
+
if (iC < 65 || iC > 127 || (iC > 90 && iC < 97)) {
|
|
8
|
+
aRet[i] = '&#' + iC + ';';
|
|
9
|
+
} else {
|
|
10
|
+
aRet[i] = str[i];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return aRet.join('');
|
|
14
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as jsx from "@miqro/jsx";
|
|
2
|
+
|
|
3
|
+
interface LogLine { out: string; identifier: string; level: "error" | "warn" | "debug" | "trace" | "info" }
|
|
4
|
+
|
|
5
|
+
export interface LogSocket {
|
|
6
|
+
lines: LogLine[];
|
|
7
|
+
clearLog: () => void;
|
|
8
|
+
getMaxlogsize: () => number | "unlimited";
|
|
9
|
+
setMaxLogSize: (val: number | "unlimited") => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useLogSocket(options: { disableLog?: boolean; }): LogSocket {
|
|
13
|
+
|
|
14
|
+
const [_, setmaxLogSize, getMaxlogsize] = jsx.useState<number | "unlimited">(1000000);
|
|
15
|
+
|
|
16
|
+
const [__, setlines, getLines] = jsx.useState<LogLine[]>([]);
|
|
17
|
+
const refresh = jsx.useRefresh();
|
|
18
|
+
|
|
19
|
+
jsx.useEffect(() => {
|
|
20
|
+
|
|
21
|
+
let timeout;
|
|
22
|
+
|
|
23
|
+
function setupSocket() {
|
|
24
|
+
try {
|
|
25
|
+
if (options.disableLog) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log("setting up log socket");
|
|
29
|
+
const socket = new WebSocket("/admin/socket");
|
|
30
|
+
socket.addEventListener("error", (err) => {
|
|
31
|
+
console.error(err);
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
timeout = setTimeout(() => {
|
|
34
|
+
setupSocket();
|
|
35
|
+
}, 1000);
|
|
36
|
+
});
|
|
37
|
+
socket.addEventListener("open", () => {
|
|
38
|
+
console.log("log socket open");
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
socket.addEventListener("message", (msg) => {
|
|
41
|
+
const lines = getLines();
|
|
42
|
+
const data = JSON.parse(msg.data);
|
|
43
|
+
//console.log(data.out);
|
|
44
|
+
const maxLogSize = getMaxlogsize();
|
|
45
|
+
if (maxLogSize !== "unlimited" && lines.length >= maxLogSize) {
|
|
46
|
+
lines.splice(0, (lines.length - maxLogSize) + 1);
|
|
47
|
+
}
|
|
48
|
+
lines.push(data);
|
|
49
|
+
setlines(lines);
|
|
50
|
+
refresh();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
socket.addEventListener("close", () => {
|
|
54
|
+
console.log("log socket close");
|
|
55
|
+
clearTimeout(timeout);
|
|
56
|
+
timeout = setTimeout(() => {
|
|
57
|
+
setupSocket();
|
|
58
|
+
}, 1000);
|
|
59
|
+
});
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error(e);
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
timeout = setTimeout(() => {
|
|
64
|
+
setupSocket();
|
|
65
|
+
}, 1000);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setupSocket();
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
lines: getLines(),
|
|
74
|
+
clearLog: () => {
|
|
75
|
+
setlines([]);
|
|
76
|
+
},
|
|
77
|
+
getMaxlogsize,
|
|
78
|
+
setMaxLogSize: (newValue: number | "unlimited") => {
|
|
79
|
+
if (newValue === "unlimited") {
|
|
80
|
+
setmaxLogSize(newValue);
|
|
81
|
+
} else {
|
|
82
|
+
setmaxLogSize(newValue);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|