mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
These packages are obsoleted by the promises API to the built-in Node fs module. The fs-extra package is also causing problems with broken APIs that don't behave the same as Node's fs module, and throwing errors without code properties on them.
117 lines
4.0 KiB
TypeScript
117 lines
4.0 KiB
TypeScript
import path from "path";
|
|
import fs from "node:fs/promises";
|
|
|
|
import type Controller from "./Controller";
|
|
import type WsServerConnector from "./WsServerConnector";
|
|
|
|
import * as lib from "@clusterio/lib";
|
|
const { logger } = lib;
|
|
import * as routes from "./routes";
|
|
|
|
|
|
/**
|
|
* Base class for controller connections
|
|
*
|
|
* @extends module:lib.Link
|
|
* @alias module:controller/src/BaseConnection
|
|
*/
|
|
export default class BaseConnection extends lib.Link {
|
|
declare "connector": WsServerConnector;
|
|
|
|
constructor(
|
|
connector: lib.WebSocketBaseConnector,
|
|
public _controller: Controller
|
|
) {
|
|
super(connector);
|
|
this.router = _controller.router;
|
|
for (let [Request, handler] of this._controller._registeredRequests) { this.handle(Request, handler); }
|
|
for (let [Request, handler] of this._controller._fallbackedRequests) { this.fallbackRequest(Request, handler); }
|
|
for (let [Event, handler] of this._controller._registeredEvents) { this.handle(Event, handler); }
|
|
for (let [Event, handler] of this._controller._snoopedEvents) { this.snoopEvent(Event, handler); }
|
|
|
|
this.handle(lib.ModPackGetRequest, this.handleModPackGetRequest.bind(this));
|
|
this.handle(lib.ModPackGetDefaultRequest, this.handleModPackGetDefaultRequest.bind(this));
|
|
this.handle(lib.ModDownloadRequest, this.handleModDownloadRequest.bind(this));
|
|
this.handle(lib.FactorioVersionsRequest, this.handleFactorioVersionsRequest.bind(this));
|
|
|
|
this.handle(lib.SubscriptionRequest, this.handleSubscriptionRequest.bind(this));
|
|
this.connector.on("close", () => {
|
|
this._controller.subscriptions.unsubscribeLink(this);
|
|
});
|
|
}
|
|
|
|
async disconnect(code: number, reason: string) {
|
|
try {
|
|
await this.connector.disconnect(code, reason);
|
|
} catch (err: any) {
|
|
if (!(err instanceof lib.SessionLost)) {
|
|
logger.error(`"Unexpected error preparing disconnect:\n${err.stack}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* True if the link is connected, not in the dropped state and not in
|
|
* the process of disconnecting.
|
|
*/
|
|
get connected(): boolean {
|
|
return this.connector.connected;
|
|
}
|
|
|
|
async handleModPackGetRequest(request: lib.ModPackGetRequest): Promise<lib.ModPack> {
|
|
let { id } = request;
|
|
let modPack = this._controller.modPacks.get(id);
|
|
if (!modPack) {
|
|
throw new lib.RequestError(`Mod pack with ID ${id} does not exist`);
|
|
}
|
|
return modPack;
|
|
}
|
|
|
|
async handleModPackGetDefaultRequest(): Promise<lib.ModPack> {
|
|
let id = this._controller.config.get("controller.default_mod_pack_id");
|
|
if (id === null) {
|
|
throw new lib.RequestError("Default mod pack not set on controller");
|
|
}
|
|
let modPack = this._controller.modPacks.get(id);
|
|
if (!modPack) {
|
|
throw new lib.RequestError(`Default mod pack configured (${id}) does not exist`);
|
|
}
|
|
return modPack;
|
|
}
|
|
|
|
getMod(mod: { name: string, version: lib.FullVersion, sha1?: string }) {
|
|
let filename = lib.ModInfo.filename(mod.name, mod.version);
|
|
let modInfo = this._controller.modStore.files.get(filename);
|
|
if (!modInfo) {
|
|
throw new lib.RequestError(`Mod ${filename} does not exist on controller`);
|
|
}
|
|
if (mod.sha1 && mod.sha1 !== modInfo.sha1) {
|
|
throw new lib.RequestError(`Mod ${filename} checksum does not match controller's checksum`);
|
|
}
|
|
return modInfo;
|
|
}
|
|
|
|
async handleModDownloadRequest(request: lib.ModDownloadRequest) {
|
|
let mod = this.getMod(request);
|
|
let modPath = path.join(this._controller.config.get("controller.mods_directory"), mod.filename);
|
|
// Open source file before creating the stream in case it throws.
|
|
let source = (await fs.open(modPath)).createReadStream();
|
|
|
|
let stream = await routes.createProxyStream(this._controller.app);
|
|
stream.filename = mod.filename;
|
|
stream.source = source;
|
|
stream.mime = "application/zip";
|
|
stream.size = String(mod.size);
|
|
|
|
return stream.id;
|
|
}
|
|
|
|
async handleSubscriptionRequest(request: lib.SubscriptionRequest, src: lib.Address, dst: lib.Address) {
|
|
return await this._controller.subscriptions.handleRequest(this, request, src, dst);
|
|
}
|
|
|
|
async handleFactorioVersionsRequest(request: lib.FactorioVersionsRequest) {
|
|
return await this._controller.factorioVersions.get(request.maxAgeMs);
|
|
}
|
|
}
|