Improve typing of various controller entities

This commit is contained in:
Hornwitser committed 2023-12-03 19:59:14 +01:00
1 parent 8b0d7a67b5
commit 94cb607930
5 files changed
+58 -44

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ import ControllerRouter from "./ControllerRouter";
* @alias module:controller/src/BaseConnection
*/
export default class BaseConnection extends lib.Link {
declare connector: lib.WebSocketBaseConnector;
declare ["connector"]: WsServerConnector;
constructor(
connector: lib.WebSocketBaseConnector,
+4 -4
View File
@@ -88,9 +88,9 @@ export default class ControlConnection extends BaseConnection {
this.handle(lib.InstanceConfigSetFieldRequest, this.handleInstanceConfigSetFieldRequest.bind(this));
this.handle(lib.InstanceConfigSetPropRequest, this.handleInstanceConfigSetPropRequest.bind(this));
this.handle(lib.InstanceAssignRequest, this.handleInstanceAssignRequest.bind(this));
this.handle(lib.InstanceRenameSaveRequest, this._controller.sendToHostByInstanceId.bind(this._controller));
this.handle(lib.InstanceCopySaveRequest, this._controller.sendToHostByInstanceId.bind(this._controller));
this.handle(lib.InstanceDeleteSaveRequest, this._controller.sendToHostByInstanceId.bind(this._controller));
this.handle(lib.InstanceRenameSaveRequest, controller.sendRequestToHostByInstanceId.bind(controller));
this.handle(lib.InstanceCopySaveRequest, controller.sendRequestToHostByInstanceId.bind(controller));
this.handle(lib.InstanceDeleteSaveRequest, controller.sendRequestToHostByInstanceId.bind(controller));
this.handle(lib.InstanceDownloadSaveRequest, this.handleInstanceDownloadSaveRequest.bind(this));
this.handle(lib.InstanceTransferSaveRequest, this.handleInstanceTransferSaveRequest.bind(this));
this.handle(lib.ModPackListRequest, this.handleModPackListRequest.bind(this));
@@ -576,7 +576,7 @@ export default class ControlConnection extends BaseConnection {
stream.filename = mod.filename;
stream.source = fs.createReadStream(modPath);
stream.mime = "application/zip";
stream.size = mod.size;
stream.size = String(mod.size);
return stream.id;
}
+10 -6
View File
@@ -36,6 +36,8 @@ const logSizeGauge = new Gauge(
"Size of all log files currently stored on the controller."
);
type InstanceId = { instanceId: number };
/**
* Manages all controller related operations
* @alias module:controller/src/Controller
@@ -1207,17 +1209,19 @@ export default class Controller {
}
}
async sendToHostByInstanceId(requestOrEvent: any) {
async sendToHostByInstanceId<Req extends InstanceId, Res>(request: Req & lib.Request<Req, Res>): Promise<Res>;
sendToHostByInstanceId<T extends InstanceId>(event: T & lib.Event<T>): void;
async sendToHostByInstanceId(requestOrEvent: lib.Request<unknown, unknown> | lib.Event<unknown>) {
if (requestOrEvent.constructor.type === "request") {
return this.sendRequestToHostByInstanceId(requestOrEvent);
return this.sendRequestToHostByInstanceId(requestOrEvent as any);
}
if (requestOrEvent.constructor.type === "event") {
return this.sendEventToHostByInstanceId(requestOrEvent);
return this.sendEventToHostByInstanceId(requestOrEvent as any);
}
throw Error(`Unknown type ${requestOrEvent.constructor.type}.`);
throw Error(`Unknown type ${(requestOrEvent.constructor as any).type}.`);
}
async sendRequestToHostByInstanceId(request: any) {
async sendRequestToHostByInstanceId<Req extends InstanceId, Res>(request: Req & lib.Request<Req, Res>) {
let instance = this.getRequestInstance(request.instanceId);
let hostId = instance.config.get("instance.assigned_host");
if (hostId === null) {
@@ -1230,7 +1234,7 @@ export default class Controller {
return await connection.send(request);
}
sendEventToHostByInstanceId(event: any) {
sendEventToHostByInstanceId<T extends { instanceId: number }>(event: T & lib.Event<T>) {
let instance = this.getRequestInstance(event.instanceId);
let hostId = instance.config.get("instance.assigned_host");
if (hostId === null) {
@@ -25,7 +25,6 @@ export interface HostInfo {
* @alias module:controller/src/HostConnection
*/
export default class HostConnection extends BaseConnection {
declare connector: WsServerConnector;
private _agent: any;
private _id: any;
private _name: any;
+43 -32
View File
@@ -16,6 +16,17 @@ const { logger } = lib;
const finished = util.promisify(nodeStream.finished);
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Express {
export interface Locals {
controller: Controller,
mainBundle: string,
devPlugins: Map<string, number>,
streams: Map<string, ProxyStream>
}
}
}
// Merges samples from sourceResult to destinationResult
function mergeSamples(destinationResult: lib.CollectorResultSerialized, sourceResult: lib.CollectorResultSerialized) {
@@ -95,14 +106,14 @@ async function getMetrics(req: Request, res: Response, next: any) {
function getPlugins(req: Request, res: Response) {
let plugins: lib.PluginWebApi[] = [];
for (let pluginInfo of (req.app.locals.controller as Controller).pluginInfos) {
for (let pluginInfo of req.app.locals.controller.pluginInfos) {
let name = pluginInfo.name;
let loaded = req.app.locals.controller.plugins.has(name);
let enabled = loaded && req.app.locals.controller.config.group(pluginInfo.name).get("load_plugin");
let enabled = loaded && req.app.locals.controller.config.group(pluginInfo.name).get("load_plugin") as boolean;
let web: { main:any, error:string|undefined } = { main: undefined, error: undefined};
let devPlugins = req.app.locals.devPlugins;
if (devPlugins && devPlugins.has(name)) {
let stats = res.locals.webpack.devMiddleware.stats.stats[devPlugins.get(name)];
let stats = res.locals.webpack.devMiddleware.stats.stats[devPlugins.get(name)!];
web.main = stats.toJson().assetsByChunkName[name];
} else if (pluginInfo.manifest) {
web.main = pluginInfo.manifest[`${pluginInfo.name}.js`];
@@ -137,7 +148,7 @@ function validateHostToken(req: Request, res: Response, next: any) {
if (typeof tokenPayload === "string") {
throw new Error("unexpected JsonWebToken type");
}
let host = (req.app.locals.controller as Controller).hosts.get(tokenPayload.host);
let host = req.app.locals.controller.hosts.get(tokenPayload.host);
if (!host) {
throw new Error("invalid host");
}
@@ -251,12 +262,12 @@ async function uploadExport(req: Request, res: Response) {
}
interface ProxyStream {
export interface ProxyStream {
id: string;
source: nodeStream.Readable | null;
flowing: boolean;
size: number | null;
mime: string | null;
size?: string;
mime?: string;
filename: string | null;
events: events.EventEmitter;
timeout: ReturnType<typeof setTimeout>;
@@ -269,8 +280,8 @@ export async function createProxyStream(app: Application): Promise<ProxyStream>
id,
source: null,
flowing: false,
size: null,
mime: null,
size: undefined,
mime: undefined,
filename: null,
events: new events.EventEmitter(),
timeout: setTimeout(() => {
@@ -289,7 +300,7 @@ export async function createProxyStream(app: Application): Promise<ProxyStream>
}
async function putStream(req: Request, res: Response) {
let stream = req.app.locals.streams.get(req.params.id);
const stream = req.app.locals.streams.get(req.params.id);
if (!stream || stream.source) {
res.sendStatus(404);
return;
@@ -309,35 +320,35 @@ async function putStream(req: Request, res: Response) {
});
}
function startStream(res: Response, stream: ProxyStream) {
res.append("Content-Type", stream.mime);
if (stream.size) {
res.append("Content-Length", stream.size);
}
if (stream.filename) {
res.append("Content-Disposition", `attachment; filename="${stream.filename}"`);
} else {
res.append("Content-Disposition", "attachment");
}
stream.source!.pipe(res);
stream.flowing = true;
res.on("close", () => {
stream.events.emit("close");
});
clearTimeout(stream.timeout);
}
async function getStream(req: Request, res: Response) {
let stream = req.app.locals.streams.get(req.params.id);
const stream = req.app.locals.streams.get(req.params.id);
if (!stream || stream.flowing) {
res.sendStatus(404);
return;
}
function startStream() {
res.append("Content-Type", stream.mime);
if (stream.size) {
res.append("Content-Length", stream.size);
}
if (stream.filename) {
res.append("Content-Disposition", `attachment; filename="${stream.filename}"`);
} else {
res.append("Content-Disposition", "attachment");
}
stream.source.pipe(res);
stream.flowing = true;
res.on("close", () => {
stream.events.emit("close");
});
clearTimeout(stream.timeout);
}
if (stream.source) {
startStream();
startStream(res, stream);
} else {
stream.events.on("source", startStream);
stream.events.on("source", () => startStream(res, stream));
stream.events.on("timeout", () => {
res.sendStatus(500);
});
@@ -377,7 +388,7 @@ async function uploadSave(req: Request, res: Response) {
let proxyStream = await createProxyStream(req.app);
proxyStream.source = stream;
proxyStream.mime = streamMime;
let timeout = new Promise((_, reject) => {
let timeout = new Promise<never>((_, reject) => {
proxyStream.events.on("timeout", () => {
stream.resume();
reject(new Error("Timed out establishing stream to host"));