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: #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": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@types/express": "^5",
 | 
					        "@types/express": "^5",
 | 
				
			||||||
        "@types/morgan": "^1.9.9",
 | 
					        "@types/morgan": "^1.9.9",
 | 
				
			||||||
 | 
					        "@types/ws": "^8.18.1",
 | 
				
			||||||
        "crc-32": "^1.2.2",
 | 
					        "crc-32": "^1.2.2",
 | 
				
			||||||
        "express": "^5",
 | 
					        "express": "^5",
 | 
				
			||||||
        "json-with-bigint": "^3.4.4",
 | 
					        "json-with-bigint": "^3.4.4",
 | 
				
			||||||
@ -21,7 +22,8 @@
 | 
				
			|||||||
        "warframe-public-export-plus": "^0.5.68",
 | 
					        "warframe-public-export-plus": "^0.5.68",
 | 
				
			||||||
        "warframe-riven-info": "^0.1.2",
 | 
					        "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
        "winston": "^3.17.0",
 | 
					        "winston": "^3.17.0",
 | 
				
			||||||
        "winston-daily-rotate-file": "^5.0.0"
 | 
					        "winston-daily-rotate-file": "^5.0.0",
 | 
				
			||||||
 | 
					        "ws": "^8.18.2"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
					        "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
				
			||||||
@ -472,6 +474,15 @@
 | 
				
			|||||||
        "@types/webidl-conversions": "*"
 | 
					        "@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": {
 | 
					    "node_modules/@typescript-eslint/eslint-plugin": {
 | 
				
			||||||
      "version": "8.32.0",
 | 
					      "version": "8.32.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
 | 
					      "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==",
 | 
					      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
 | 
				
			||||||
      "license": "ISC"
 | 
					      "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": {
 | 
					    "node_modules/xtend": {
 | 
				
			||||||
      "version": "4.0.2",
 | 
					      "version": "4.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@types/express": "^5",
 | 
					    "@types/express": "^5",
 | 
				
			||||||
    "@types/morgan": "^1.9.9",
 | 
					    "@types/morgan": "^1.9.9",
 | 
				
			||||||
 | 
					    "@types/ws": "^8.18.1",
 | 
				
			||||||
    "crc-32": "^1.2.2",
 | 
					    "crc-32": "^1.2.2",
 | 
				
			||||||
    "express": "^5",
 | 
					    "express": "^5",
 | 
				
			||||||
    "json-with-bigint": "^3.4.4",
 | 
					    "json-with-bigint": "^3.4.4",
 | 
				
			||||||
@ -28,7 +29,8 @@
 | 
				
			|||||||
    "warframe-public-export-plus": "^0.5.68",
 | 
					    "warframe-public-export-plus": "^0.5.68",
 | 
				
			||||||
    "warframe-riven-info": "^0.1.2",
 | 
					    "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
    "winston": "^3.17.0",
 | 
					    "winston": "^3.17.0",
 | 
				
			||||||
    "winston-daily-rotate-file": "^5.0.0"
 | 
					    "winston-daily-rotate-file": "^5.0.0",
 | 
				
			||||||
 | 
					    "ws": "^8.18.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ import fs from "fs";
 | 
				
			|||||||
import fsPromises from "fs/promises";
 | 
					import fsPromises from "fs/promises";
 | 
				
			||||||
import { logger } from "../utils/logger";
 | 
					import { logger } from "../utils/logger";
 | 
				
			||||||
import { config, configPath, loadConfig } from "./configService";
 | 
					import { config, configPath, loadConfig } from "./configService";
 | 
				
			||||||
import { getWebPorts, startWebServer, stopWebServer } from "./webService";
 | 
					import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let amnesia = false;
 | 
					let amnesia = false;
 | 
				
			||||||
fs.watchFile(configPath, () => {
 | 
					fs.watchFile(configPath, () => {
 | 
				
			||||||
@ -21,7 +21,13 @@ fs.watchFile(configPath, () => {
 | 
				
			|||||||
        const webPorts = getWebPorts();
 | 
					        const webPorts = getWebPorts();
 | 
				
			||||||
        if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
 | 
					        if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
 | 
				
			||||||
            logger.info(`Restarting web server to apply port changes.`);
 | 
					            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);
 | 
					            void stopWebServer().then(startWebServer);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            sendWsBroadcast({ config_reloaded: true });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -5,9 +5,12 @@ import { config } from "./configService";
 | 
				
			|||||||
import { logger } from "../utils/logger";
 | 
					import { logger } from "../utils/logger";
 | 
				
			||||||
import { app } from "../app";
 | 
					import { app } from "../app";
 | 
				
			||||||
import { AddressInfo } from "node:net";
 | 
					import { AddressInfo } from "node:net";
 | 
				
			||||||
 | 
					import ws from "ws";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let httpServer: http.Server | undefined;
 | 
					let httpServer: http.Server | undefined;
 | 
				
			||||||
let httpsServer: https.Server | undefined;
 | 
					let httpsServer: https.Server | undefined;
 | 
				
			||||||
 | 
					let wsServer: ws.Server | undefined;
 | 
				
			||||||
 | 
					let wssServer: ws.Server | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const tlsOptions = {
 | 
					const tlsOptions = {
 | 
				
			||||||
    key: fs.readFileSync("static/certs/key.pem"),
 | 
					    key: fs.readFileSync("static/certs/key.pem"),
 | 
				
			||||||
@ -21,10 +24,17 @@ export const startWebServer = (): void => {
 | 
				
			|||||||
    // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
					    // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
    httpServer = http.createServer(app);
 | 
					    httpServer = http.createServer(app);
 | 
				
			||||||
    httpServer.listen(httpPort, () => {
 | 
					    httpServer.listen(httpPort, () => {
 | 
				
			||||||
 | 
					        wsServer = new ws.Server({ server: httpServer });
 | 
				
			||||||
 | 
					        //wsServer.on("connection", wsOnConnect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logger.info("HTTP server started on port " + httpPort);
 | 
					        logger.info("HTTP server started on port " + httpPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
					        // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
        httpsServer = https.createServer(tlsOptions, app);
 | 
					        httpsServer = https.createServer(tlsOptions, app);
 | 
				
			||||||
        httpsServer.listen(httpsPort, () => {
 | 
					        httpsServer.listen(httpsPort, () => {
 | 
				
			||||||
 | 
					            wssServer = new ws.Server({ server: httpsServer });
 | 
				
			||||||
 | 
					            //wssServer.on("connection", wsOnConnect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            logger.info("HTTPS server started on port " + httpsPort);
 | 
					            logger.info("HTTPS server started on port " + httpsPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            logger.info(
 | 
					            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);
 | 
					    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;
 | 
					let loginOrRegisterPending = false;
 | 
				
			||||||
window.registerSubmit = false;
 | 
					window.registerSubmit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1822,6 +1842,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
				
			|||||||
            clearInterval(interval);
 | 
					            clearInterval(interval);
 | 
				
			||||||
            fetch("/custom/config?" + window.authz).then(async res => {
 | 
					            fetch("/custom/config?" + window.authz).then(async res => {
 | 
				
			||||||
                if (res.status == 200) {
 | 
					                if (res.status == 200) {
 | 
				
			||||||
 | 
					                    //window.is_admin = true;
 | 
				
			||||||
                    $("#server-settings-no-perms").addClass("d-none");
 | 
					                    $("#server-settings-no-perms").addClass("d-none");
 | 
				
			||||||
                    $("#server-settings").removeClass("d-none");
 | 
					                    $("#server-settings").removeClass("d-none");
 | 
				
			||||||
                    res.json().then(json =>
 | 
					                    res.json().then(json =>
 | 
				
			||||||
@ -1830,9 +1851,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
				
			|||||||
                            var x = document.getElementById(`${key}`);
 | 
					                            var x = document.getElementById(`${key}`);
 | 
				
			||||||
                            if (x != null) {
 | 
					                            if (x != null) {
 | 
				
			||||||
                                if (x.type == "checkbox") {
 | 
					                                if (x.type == "checkbox") {
 | 
				
			||||||
                                    if (value === true) {
 | 
					                                    x.checked = value;
 | 
				
			||||||
                                        x.setAttribute("checked", "checked");
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                } else if (x.type == "number") {
 | 
					                                } else if (x.type == "number") {
 | 
				
			||||||
                                    x.setAttribute("value", `${value}`);
 | 
					                                    x.setAttribute("value", `${value}`);
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
@ -1847,6 +1866,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        //window.is_admin = false;
 | 
				
			||||||
                        $("#server-settings-no-perms").removeClass("d-none");
 | 
					                        $("#server-settings-no-perms").removeClass("d-none");
 | 
				
			||||||
                        $("#server-settings").addClass("d-none");
 | 
					                        $("#server-settings").addClass("d-none");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user