* feat: express decorators for rest apis and websocket * fix: added package dependency * fix: refactor decorators
85 lines
2.2 KiB
TypeScript
85 lines
2.2 KiB
TypeScript
import { Router, Request } from "express";
|
|
import type { WebSocket } from "ws";
|
|
import "reflect-metadata";
|
|
|
|
interface ControllerInstance {
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
interface ControllerConstructor {
|
|
new (...args: any[]): ControllerInstance;
|
|
prototype: ControllerInstance;
|
|
}
|
|
|
|
export function registerWebSocketControllers(
|
|
router: Router,
|
|
Controller: ControllerConstructor,
|
|
existingInstance?: ControllerInstance,
|
|
): void {
|
|
const instance = existingInstance || new Controller();
|
|
const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string;
|
|
|
|
Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => {
|
|
if (methodName === "constructor") return; // Skip the constructor
|
|
|
|
const method = Reflect.getMetadata(
|
|
"method",
|
|
instance,
|
|
methodName,
|
|
) as string;
|
|
const route = Reflect.getMetadata("route", instance, methodName) as string;
|
|
|
|
if (method === "ws" && route) {
|
|
const handler = instance[methodName] as unknown;
|
|
|
|
if (
|
|
typeof handler === "function" &&
|
|
typeof (router as any).ws === "function"
|
|
) {
|
|
(router as any).ws(
|
|
`${baseRoute}${route}`,
|
|
(ws: WebSocket, req: Request) => {
|
|
try {
|
|
handler.call(instance, ws, req);
|
|
} catch (error) {
|
|
console.error(
|
|
`WebSocket error in ${Controller.name}.${methodName}`,
|
|
error,
|
|
);
|
|
ws.close(
|
|
1011,
|
|
error instanceof Error
|
|
? error.message
|
|
: "Internal server error",
|
|
);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Base controller class for WebSocket endpoints
|
|
*/
|
|
export abstract class BaseWebSocketController {
|
|
protected router: Router;
|
|
|
|
constructor() {
|
|
this.router = Router();
|
|
}
|
|
|
|
/**
|
|
* Get the base route for this controller
|
|
*/
|
|
protected getBaseRoute(): string {
|
|
return Reflect.getMetadata("baseRoute", this.constructor) || "";
|
|
}
|
|
|
|
/**
|
|
* Abstract method to handle WebSocket connections
|
|
* Implement this in your derived class
|
|
*/
|
|
abstract handleConnection(ws: WebSocket, req: Request): void;
|
|
}
|