165 lines
4.2 KiB
TypeScript
165 lines
4.2 KiB
TypeScript
import type {
|
|
WebSocketConnectionMiddleware,
|
|
WebSocketMessageMiddleware,
|
|
WebSocketReceiveMiddleware,
|
|
MiddlewareConfig,
|
|
MiddlewareContext,
|
|
} from './types';
|
|
import type { WebSocketConfig, WebSocketMessage } from '../websocket/types';
|
|
import { MiddlewareError } from '../errors';
|
|
|
|
/**
|
|
* Middleware chain executor for WebSocket connections
|
|
*/
|
|
export class WebSocketMiddlewareChain {
|
|
private connectionMiddleware: Array<{
|
|
middleware: WebSocketConnectionMiddleware;
|
|
config: MiddlewareConfig;
|
|
}> = [];
|
|
|
|
private messageMiddleware: Array<{
|
|
middleware: WebSocketMessageMiddleware;
|
|
config: MiddlewareConfig;
|
|
}> = [];
|
|
|
|
private receiveMiddleware: Array<{
|
|
middleware: WebSocketReceiveMiddleware;
|
|
config: MiddlewareConfig;
|
|
}> = [];
|
|
|
|
/**
|
|
* Add connection middleware
|
|
*/
|
|
addConnectionMiddleware(
|
|
middleware: WebSocketConnectionMiddleware,
|
|
config: MiddlewareConfig = {},
|
|
): void {
|
|
this.connectionMiddleware.push({ middleware, config });
|
|
this.sortByPriority(this.connectionMiddleware);
|
|
}
|
|
|
|
/**
|
|
* Add message middleware
|
|
*/
|
|
addMessageMiddleware(
|
|
middleware: WebSocketMessageMiddleware,
|
|
config: MiddlewareConfig = {},
|
|
): void {
|
|
this.messageMiddleware.push({ middleware, config });
|
|
this.sortByPriority(this.messageMiddleware);
|
|
}
|
|
|
|
/**
|
|
* Add receive middleware
|
|
*/
|
|
addReceiveMiddleware(
|
|
middleware: WebSocketReceiveMiddleware,
|
|
config: MiddlewareConfig = {},
|
|
): void {
|
|
this.receiveMiddleware.push({ middleware, config });
|
|
this.sortByPriority(this.receiveMiddleware);
|
|
}
|
|
|
|
/**
|
|
* Execute connection middleware chain
|
|
*/
|
|
async executeConnection(config: WebSocketConfig): Promise<WebSocketConfig> {
|
|
const context = this.createContext(config.metadata);
|
|
let current = config;
|
|
|
|
for (const { middleware, config: mwConfig } of this.connectionMiddleware) {
|
|
if (mwConfig.enabled === false) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
current = await middleware(current, context);
|
|
} catch (error) {
|
|
throw new MiddlewareError(
|
|
`Connection middleware failed: ${mwConfig.name || 'unknown'}`,
|
|
mwConfig.name || 'unknown',
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
/**
|
|
* Execute message middleware chain
|
|
*/
|
|
async executeMessage<T>(message: WebSocketMessage<T>): Promise<WebSocketMessage<T>> {
|
|
const context = this.createContext();
|
|
let current = message;
|
|
|
|
for (const { middleware, config: mwConfig } of this.messageMiddleware) {
|
|
if (mwConfig.enabled === false) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
current = await middleware(current, context);
|
|
} catch (error) {
|
|
throw new MiddlewareError(
|
|
`Message middleware failed: ${mwConfig.name || 'unknown'}`,
|
|
mwConfig.name || 'unknown',
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
/**
|
|
* Execute receive middleware chain
|
|
*/
|
|
async executeReceive<T>(
|
|
event: string,
|
|
data: T,
|
|
): Promise<{ event: string; data: T }> {
|
|
const context = this.createContext();
|
|
let current = { event, data };
|
|
|
|
for (const { middleware, config: mwConfig } of this.receiveMiddleware) {
|
|
if (mwConfig.enabled === false) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
current = await middleware(current.event, current.data, context);
|
|
} catch (error) {
|
|
throw new MiddlewareError(
|
|
`Receive middleware failed: ${mwConfig.name || 'unknown'}`,
|
|
mwConfig.name || 'unknown',
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
/**
|
|
* Sort middleware by priority (higher first)
|
|
*/
|
|
private sortByPriority<T extends { config: MiddlewareConfig }>(middleware: Array<T>): void {
|
|
middleware.sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0));
|
|
}
|
|
|
|
/**
|
|
* Create middleware execution context
|
|
*/
|
|
private createContext(metadata: Record<string, unknown> = {}): MiddlewareContext {
|
|
return {
|
|
metadata: { ...metadata },
|
|
abort: (reason: string) => {
|
|
throw new MiddlewareError(`Middleware chain aborted: ${reason}`, 'chain');
|
|
},
|
|
skip: () => {
|
|
// No-op - actual implementation would use control flow
|
|
},
|
|
};
|
|
}
|
|
}
|