Files
factorio-clusterio/packages/web_ui/src/util/websocket.jsx
T
Hornwitser 1c8a2fef32 Add log inspection commands
Add log query and log follow commands which allows inspection of the
combined cluster log.  Past entries can be queried via the new queryLog
request.  The log is stored into a single flat file for now, though the
performance of this may good enough.
2020-11-30 02:49:06 +01:00

136 lines
3.2 KiB
React

import libLink from "@clusterio/lib/link";
import libPlugin from "@clusterio/lib/plugin";
import libErrors from "@clusterio/lib/errors";
import { logger } from "@clusterio/lib/logging";
import packageJson from "../../package.json";
/**
* Connector for control connection to master server
* @private
*/
export class ControlConnector extends libLink.WebSocketClientConnector {
constructor(url, reconnectDelay) {
super(url, reconnectDelay);
this.token = null;
}
register() {
if (!this.token) {
throw new Error("Token not set");
}
logger.verbose("SOCKET | registering control");
this.sendHandshake("register_control", {
token: this.token,
agent: "Clusterio Web UI",
version: packageJson.version,
});
}
}
/**
* Handles running the control
*
* Connects to the master server over WebSocket and sends commands to it.
* @static
*/
export class Control extends libLink.Link {
constructor(connector, controlPlugins) {
super("control", "master", connector);
libLink.attachAllMessages(this);
/**
* Mapping of plugin names to their instance for loaded plugins.
* @type {Map<string, module:lib/plugin.BaseControlPlugin>}
*/
this.plugins = controlPlugins;
for (let controlPlugin of controlPlugins.values()) {
libPlugin.attachPluginMessages(this, controlPlugin.info, controlPlugin);
}
this.instanceLogHandlers = new Map();
this.connector.on("connect", () => {
this.updateLogSubscriptions().catch(err => logger.error(
`Unexpected error updating log subscriptions:\n${err.stack}`
));
});
}
async logMessageEventHandler(message) {
let info = message.data.info;
if (info.instance_id !== undefined) {
let instanceHandlers = this.instanceLogHandlers.get(info.instance_id);
for (let handler of instanceHandlers || []) {
handler(info);
}
}
}
async onInstanceLog(id, handler) {
if (!Number.isInteger(id)) {
throw new Error("Invalid instance id");
}
let handlers = this.instanceLogHandlers.get(id);
if (!handlers) {
handlers = [];
this.instanceLogHandlers.set(id, handlers);
}
handlers.push(handler);
if (handlers.length === 1) {
await this.updateLogSubscriptions();
}
}
async offInstanceLog(id, handler) {
let handlers = this.instanceLogHandlers.get(id);
if (!handlers || !handlers.length) {
throw new Error(`No handlers for instance ${id} exist`);
}
let index = handlers.lastIndexOf(handler);
if (index === -1) {
throw new Error(`Given handler is not registered for instance ${id}`);
}
handlers.splice(index, 1);
if (!handlers.length) {
await this.updateLogSubscriptions();
}
}
async updateLogSubscriptions() {
await libLink.messages.setLogSubscriptions.send(this, {
all: false,
master: false,
slave_ids: [],
instance_ids: [...this.instanceLogHandlers.keys()],
max_level: null,
});
}
async debugWsMessageEventHandler(message) {
// eslint-disable-next-line no-console
console.log("WS", message.data.direction, message.data.content);
}
async shutdown() {
this.connector.setTimeout(30);
try {
await libLink.messages.prepareDisconnect.send(this);
} catch (err) {
if (!(err instanceof libErrors.SessionLost)) {
throw err;
}
}
await this.connector.close(1000, "Control Quit");
}
}