XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFESpaceNinjaServer

feat(webui): initial websocket integration to be more responsive (#2221)

For now just handles changes to config.json but in the future might keep the inventory tabs up-to-date with in-game actions. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2221 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

4cb0f8b1
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

5 个文件 +112 -6
Modified package-lock.json +33 -1
@@ -11,6 +11,7 @@
11 11 "dependencies": {
12 12 "@types/express": "^5",
13 13 "@types/morgan": "^1.9.9",
14 "@types/ws": "^8.18.1",
14 15 "crc-32": "^1.2.2",
15 16 "express": "^5",
16 17 "json-with-bigint": "^3.4.4",
@@ -21,7 +22,8 @@
21 22 "warframe-public-export-plus": "^0.5.68",
22 23 "warframe-riven-info": "^0.1.2",
23 24 "winston": "^3.17.0",
24 "winston-daily-rotate-file": "^5.0.0"
25 "winston-daily-rotate-file": "^5.0.0",
26 "ws": "^8.18.2"
25 27 },
26 28 "devDependencies": {
27 29 "@typescript-eslint/eslint-plugin": "^8.28.0",
@@ -472,6 +474,15 @@
472 474 "@types/webidl-conversions": "*"
473 475 }
474 476 },
477 "node_modules/@types/ws": {
478 "version": "8.18.1",
479 "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
480 "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
481 "license": "MIT",
482 "dependencies": {
483 "@types/node": "*"
484 }
485 },
475 486 "node_modules/@typescript-eslint/eslint-plugin": {
476 487 "version": "8.32.0",
477 488 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
@@ -3931,6 +3942,27 @@
3931 3942 "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
3932 3943 "license": "ISC"
3933 3944 },
3945 "node_modules/ws": {
3946 "version": "8.18.2",
3947 "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
3948 "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
3949 "license": "MIT",
3950 "engines": {
3951 "node": ">=10.0.0"
3952 },
3953 "peerDependencies": {
3954 "bufferutil": "^4.0.1",
3955 "utf-8-validate": ">=5.0.2"
3956 },
3957 "peerDependenciesMeta": {
3958 "bufferutil": {
3959 "optional": true
3960 },
3961 "utf-8-validate": {
3962 "optional": true
3963 }
3964 }
3965 },
3934 3966 "node_modules/xtend": {
3935 3967 "version": "4.0.2",
3936 3968 "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
Modified package.json +3 -1
@@ -18,6 +18,7 @@
18 18 "dependencies": {
19 19 "@types/express": "^5",
20 20 "@types/morgan": "^1.9.9",
21 "@types/ws": "^8.18.1",
21 22 "crc-32": "^1.2.2",
22 23 "express": "^5",
23 24 "json-with-bigint": "^3.4.4",
@@ -28,7 +29,8 @@
28 29 "warframe-public-export-plus": "^0.5.68",
29 30 "warframe-riven-info": "^0.1.2",
30 31 "winston": "^3.17.0",
31 "winston-daily-rotate-file": "^5.0.0"
32 "winston-daily-rotate-file": "^5.0.0",
33 "ws": "^8.18.2"
32 34 },
33 35 "devDependencies": {
34 36 "@typescript-eslint/eslint-plugin": "^8.28.0",
Modified src/services/configWatcherService.ts +7 -1
@@ -2,7 +2,7 @@ import fs from "fs";
2 2 import fsPromises from "fs/promises";
3 3 import { logger } from "../utils/logger";
4 4 import { config, configPath, loadConfig } from "./configService";
5 import { getWebPorts, startWebServer, stopWebServer } from "./webService";
5 import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
6 6
7 7 let amnesia = false;
8 8 fs.watchFile(configPath, () => {
@@ -21,7 +21,13 @@ fs.watchFile(configPath, () => {
21 21 const webPorts = getWebPorts();
22 22 if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
23 23 logger.info(`Restarting web server to apply port changes.`);
24
25 // Tell webui clients to reload with new port
26 sendWsBroadcast({ ports: { http: config.httpPort, https: config.httpsPort } });
27
24 28 void stopWebServer().then(startWebServer);
29 } else {
30 sendWsBroadcast({ config_reloaded: true });
25 31 }
26 32 }
27 33 });
Modified src/services/webService.ts +46 -0
@@ -5,9 +5,12 @@ import { config } from "./configService";
5 5 import { logger } from "../utils/logger";
6 6 import { app } from "../app";
7 7 import { AddressInfo } from "node:net";
8 import ws from "ws";
8 9
9 10 let httpServer: http.Server | undefined;
10 11 let httpsServer: https.Server | undefined;
12 let wsServer: ws.Server | undefined;
13 let wssServer: ws.Server | undefined;
11 14
12 15 const tlsOptions = {
13 16 key: fs.readFileSync("static/certs/key.pem"),
@@ -21,10 +24,17 @@ export const startWebServer = (): void => {
21 24 // eslint-disable-next-line @typescript-eslint/no-misused-promises
22 25 httpServer = http.createServer(app);
23 26 httpServer.listen(httpPort, () => {
27 wsServer = new ws.Server({ server: httpServer });
28 //wsServer.on("connection", wsOnConnect);
29
24 30 logger.info("HTTP server started on port " + httpPort);
31
25 32 // eslint-disable-next-line @typescript-eslint/no-misused-promises
26 33 httpsServer = https.createServer(tlsOptions, app);
27 34 httpsServer.listen(httpsPort, () => {
35 wssServer = new ws.Server({ server: httpsServer });
36 //wssServer.on("connection", wsOnConnect);
37
28 38 logger.info("HTTPS server started on port " + httpsPort);
29 39
30 40 logger.info(
@@ -61,5 +71,41 @@ export const stopWebServer = async (): Promise<void> => {
61 71 })
62 72 );
63 73 }
74 if (wsServer) {
75 promises.push(
76 new Promise(resolve => {
77 wsServer!.close(() => {
78 resolve();
79 });
80 })
81 );
82 }
83 if (wssServer) {
84 promises.push(
85 new Promise(resolve => {
86 wssServer!.close(() => {
87 resolve();
88 });
89 })
90 );
91 }
64 92 await Promise.all(promises);
65 93 };
94
95 /*const wsOnConnect = (ws: ws, _req: http.IncomingMessage): void => {
96 ws.on("message", console.log);
97 };*/
98
99 export const sendWsBroadcast = <T>(data: T): void => {
100 const msg = JSON.stringify(data);
101 if (wsServer) {
102 for (const client of wsServer.clients) {
103 client.send(msg);
104 }
105 }
106 if (wssServer) {
107 for (const client of wssServer.clients) {
108 client.send(msg);
109 }
110 }
111 };
Modified static/webui/script.js +23 -3
@@ -1,3 +1,23 @@
1 function openWebSocket() {
2 window.ws = new WebSocket("/custom/ws");
3 window.ws.onmessage = e => {
4 const msg = JSON.parse(e.data);
5 if ("ports" in msg) {
6 location.port = location.protocol == "https:" ? msg.ports.https : msg.ports.http;
7 }
8 if ("config_reloaded" in msg) {
9 //window.is_admin = undefined;
10 if (single.getCurrentPath() == "/webui/cheats") {
11 single.loadRoute("/webui/cheats");
12 }
13 }
14 };
15 window.ws.onclose = function () {
16 setTimeout(openWebSocket, 3000);
17 };
18 }
19 openWebSocket();
20
1 21 let loginOrRegisterPending = false;
2 22 window.registerSubmit = false;
3 23
@@ -1822,6 +1842,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
1822 1842 clearInterval(interval);
1823 1843 fetch("/custom/config?" + window.authz).then(async res => {
1824 1844 if (res.status == 200) {
1845 //window.is_admin = true;
1825 1846 $("#server-settings-no-perms").addClass("d-none");
1826 1847 $("#server-settings").removeClass("d-none");
1827 1848 res.json().then(json =>
@@ -1830,9 +1851,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
1830 1851 var x = document.getElementById(`${key}`);
1831 1852 if (x != null) {
1832 1853 if (x.type == "checkbox") {
1833 if (value === true) {
1834 x.setAttribute("checked", "checked");
1835 }
1854 x.checked = value;
1836 1855 } else if (x.type == "number") {
1837 1856 x.setAttribute("value", `${value}`);
1838 1857 }
@@ -1847,6 +1866,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
1847 1866 }
1848 1867 });
1849 1868 } else {
1869 //window.is_admin = false;
1850 1870 $("#server-settings-no-perms").removeClass("d-none");
1851 1871 $("#server-settings").addClass("d-none");
1852 1872 }