forked from OpenWF/SpaceNinjaServer
		
	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: OpenWF/SpaceNinjaServer#2221 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									eadc9c4ecb
								
							
						
					
					
						commit
						4cb0f8b167
					
				
							
								
								
									
										34
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										34
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -11,6 +11,7 @@
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/express": "^5",
 | 
			
		||||
        "@types/morgan": "^1.9.9",
 | 
			
		||||
        "@types/ws": "^8.18.1",
 | 
			
		||||
        "crc-32": "^1.2.2",
 | 
			
		||||
        "express": "^5",
 | 
			
		||||
        "json-with-bigint": "^3.4.4",
 | 
			
		||||
@ -21,7 +22,8 @@
 | 
			
		||||
        "warframe-public-export-plus": "^0.5.68",
 | 
			
		||||
        "warframe-riven-info": "^0.1.2",
 | 
			
		||||
        "winston": "^3.17.0",
 | 
			
		||||
        "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
        "winston-daily-rotate-file": "^5.0.0",
 | 
			
		||||
        "ws": "^8.18.2"
 | 
			
		||||
      },
 | 
			
		||||
      "devDependencies": {
 | 
			
		||||
        "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
			
		||||
@ -472,6 +474,15 @@
 | 
			
		||||
        "@types/webidl-conversions": "*"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@types/ws": {
 | 
			
		||||
      "version": "8.18.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
 | 
			
		||||
      "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/node": "*"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@typescript-eslint/eslint-plugin": {
 | 
			
		||||
      "version": "8.32.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
 | 
			
		||||
@ -3931,6 +3942,27 @@
 | 
			
		||||
      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
 | 
			
		||||
      "license": "ISC"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ws": {
 | 
			
		||||
      "version": "8.18.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
 | 
			
		||||
      "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "bufferutil": "^4.0.1",
 | 
			
		||||
        "utf-8-validate": ">=5.0.2"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "bufferutil": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        },
 | 
			
		||||
        "utf-8-validate": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/xtend": {
 | 
			
		||||
      "version": "4.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@types/express": "^5",
 | 
			
		||||
    "@types/morgan": "^1.9.9",
 | 
			
		||||
    "@types/ws": "^8.18.1",
 | 
			
		||||
    "crc-32": "^1.2.2",
 | 
			
		||||
    "express": "^5",
 | 
			
		||||
    "json-with-bigint": "^3.4.4",
 | 
			
		||||
@ -28,7 +29,8 @@
 | 
			
		||||
    "warframe-public-export-plus": "^0.5.68",
 | 
			
		||||
    "warframe-riven-info": "^0.1.2",
 | 
			
		||||
    "winston": "^3.17.0",
 | 
			
		||||
    "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
    "winston-daily-rotate-file": "^5.0.0",
 | 
			
		||||
    "ws": "^8.18.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import fs from "fs";
 | 
			
		||||
import fsPromises from "fs/promises";
 | 
			
		||||
import { logger } from "../utils/logger";
 | 
			
		||||
import { config, configPath, loadConfig } from "./configService";
 | 
			
		||||
import { getWebPorts, startWebServer, stopWebServer } from "./webService";
 | 
			
		||||
import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
 | 
			
		||||
 | 
			
		||||
let amnesia = false;
 | 
			
		||||
fs.watchFile(configPath, () => {
 | 
			
		||||
@ -21,7 +21,13 @@ fs.watchFile(configPath, () => {
 | 
			
		||||
        const webPorts = getWebPorts();
 | 
			
		||||
        if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
 | 
			
		||||
            logger.info(`Restarting web server to apply port changes.`);
 | 
			
		||||
 | 
			
		||||
            // Tell webui clients to reload with new port
 | 
			
		||||
            sendWsBroadcast({ ports: { http: config.httpPort, https: config.httpsPort } });
 | 
			
		||||
 | 
			
		||||
            void stopWebServer().then(startWebServer);
 | 
			
		||||
        } else {
 | 
			
		||||
            sendWsBroadcast({ config_reloaded: true });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -5,9 +5,12 @@ import { config } from "./configService";
 | 
			
		||||
import { logger } from "../utils/logger";
 | 
			
		||||
import { app } from "../app";
 | 
			
		||||
import { AddressInfo } from "node:net";
 | 
			
		||||
import ws from "ws";
 | 
			
		||||
 | 
			
		||||
let httpServer: http.Server | undefined;
 | 
			
		||||
let httpsServer: https.Server | undefined;
 | 
			
		||||
let wsServer: ws.Server | undefined;
 | 
			
		||||
let wssServer: ws.Server | undefined;
 | 
			
		||||
 | 
			
		||||
const tlsOptions = {
 | 
			
		||||
    key: fs.readFileSync("static/certs/key.pem"),
 | 
			
		||||
@ -21,10 +24,17 @@ export const startWebServer = (): void => {
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
			
		||||
    httpServer = http.createServer(app);
 | 
			
		||||
    httpServer.listen(httpPort, () => {
 | 
			
		||||
        wsServer = new ws.Server({ server: httpServer });
 | 
			
		||||
        //wsServer.on("connection", wsOnConnect);
 | 
			
		||||
 | 
			
		||||
        logger.info("HTTP server started on port " + httpPort);
 | 
			
		||||
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
			
		||||
        httpsServer = https.createServer(tlsOptions, app);
 | 
			
		||||
        httpsServer.listen(httpsPort, () => {
 | 
			
		||||
            wssServer = new ws.Server({ server: httpsServer });
 | 
			
		||||
            //wssServer.on("connection", wsOnConnect);
 | 
			
		||||
 | 
			
		||||
            logger.info("HTTPS server started on port " + httpsPort);
 | 
			
		||||
 | 
			
		||||
            logger.info(
 | 
			
		||||
@ -61,5 +71,41 @@ export const stopWebServer = async (): Promise<void> => {
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    if (wsServer) {
 | 
			
		||||
        promises.push(
 | 
			
		||||
            new Promise(resolve => {
 | 
			
		||||
                wsServer!.close(() => {
 | 
			
		||||
                    resolve();
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    if (wssServer) {
 | 
			
		||||
        promises.push(
 | 
			
		||||
            new Promise(resolve => {
 | 
			
		||||
                wssServer!.close(() => {
 | 
			
		||||
                    resolve();
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    await Promise.all(promises);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*const wsOnConnect = (ws: ws, _req: http.IncomingMessage): void => {
 | 
			
		||||
    ws.on("message", console.log);
 | 
			
		||||
};*/
 | 
			
		||||
 | 
			
		||||
export const sendWsBroadcast = <T>(data: T): void => {
 | 
			
		||||
    const msg = JSON.stringify(data);
 | 
			
		||||
    if (wsServer) {
 | 
			
		||||
        for (const client of wsServer.clients) {
 | 
			
		||||
            client.send(msg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (wssServer) {
 | 
			
		||||
        for (const client of wssServer.clients) {
 | 
			
		||||
            client.send(msg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,23 @@
 | 
			
		||||
function openWebSocket() {
 | 
			
		||||
    window.ws = new WebSocket("/custom/ws");
 | 
			
		||||
    window.ws.onmessage = e => {
 | 
			
		||||
        const msg = JSON.parse(e.data);
 | 
			
		||||
        if ("ports" in msg) {
 | 
			
		||||
            location.port = location.protocol == "https:" ? msg.ports.https : msg.ports.http;
 | 
			
		||||
        }
 | 
			
		||||
        if ("config_reloaded" in msg) {
 | 
			
		||||
            //window.is_admin = undefined;
 | 
			
		||||
            if (single.getCurrentPath() == "/webui/cheats") {
 | 
			
		||||
                single.loadRoute("/webui/cheats");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    window.ws.onclose = function () {
 | 
			
		||||
        setTimeout(openWebSocket, 3000);
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
openWebSocket();
 | 
			
		||||
 | 
			
		||||
let loginOrRegisterPending = false;
 | 
			
		||||
window.registerSubmit = false;
 | 
			
		||||
 | 
			
		||||
@ -1822,6 +1842,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
			
		||||
            clearInterval(interval);
 | 
			
		||||
            fetch("/custom/config?" + window.authz).then(async res => {
 | 
			
		||||
                if (res.status == 200) {
 | 
			
		||||
                    //window.is_admin = true;
 | 
			
		||||
                    $("#server-settings-no-perms").addClass("d-none");
 | 
			
		||||
                    $("#server-settings").removeClass("d-none");
 | 
			
		||||
                    res.json().then(json =>
 | 
			
		||||
@ -1830,9 +1851,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
			
		||||
                            var x = document.getElementById(`${key}`);
 | 
			
		||||
                            if (x != null) {
 | 
			
		||||
                                if (x.type == "checkbox") {
 | 
			
		||||
                                    if (value === true) {
 | 
			
		||||
                                        x.setAttribute("checked", "checked");
 | 
			
		||||
                                    }
 | 
			
		||||
                                    x.checked = value;
 | 
			
		||||
                                } else if (x.type == "number") {
 | 
			
		||||
                                    x.setAttribute("value", `${value}`);
 | 
			
		||||
                                }
 | 
			
		||||
@ -1847,6 +1866,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    } else {
 | 
			
		||||
                        //window.is_admin = false;
 | 
			
		||||
                        $("#server-settings-no-perms").removeClass("d-none");
 | 
			
		||||
                        $("#server-settings").addClass("d-none");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user