feat(websocket): Add TypedRouter WebSocket integration, connection registry, peer tagging and broadcast APIs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { ISmartServeInstance, IConnectionInfo } from '../core/smartserve.interfaces.js';
|
||||
import type { ISmartServeInstance, IConnectionInfo, IWebSocketPeer, IWebSocketConnectionCallbacks } from '../core/smartserve.interfaces.js';
|
||||
import { BaseAdapter, type IAdapterCharacteristics, type TRequestHandler } from './adapter.base.js';
|
||||
|
||||
// Deno types (for type checking without requiring Deno runtime)
|
||||
@@ -98,21 +98,47 @@ export class DenoAdapter extends BaseAdapter {
|
||||
|
||||
const peer = this.createWebSocketPeer(socket, request);
|
||||
|
||||
// Get internal callbacks if typedRouter mode
|
||||
const callbacks = (hooks as any)._connectionCallbacks as IWebSocketConnectionCallbacks | undefined;
|
||||
const typedRouter = hooks.typedRouter;
|
||||
|
||||
socket.onopen = () => {
|
||||
// Register connection if typedRouter mode
|
||||
if (callbacks) {
|
||||
callbacks.onRegister(peer);
|
||||
}
|
||||
hooks.onOpen?.(peer);
|
||||
};
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
const message = {
|
||||
type: typeof event.data === 'string' ? 'text' as const : 'binary' as const,
|
||||
text: typeof event.data === 'string' ? event.data : undefined,
|
||||
data: event.data instanceof Uint8Array ? event.data : undefined,
|
||||
size: typeof event.data === 'string' ? event.data.length : (event.data as ArrayBuffer).byteLength,
|
||||
};
|
||||
hooks.onMessage?.(peer, message);
|
||||
socket.onmessage = async (event) => {
|
||||
// If typedRouter is configured, route through it
|
||||
if (typedRouter && typeof event.data === 'string') {
|
||||
try {
|
||||
const requestObj = JSON.parse(event.data);
|
||||
const response = await typedRouter.routeAndAddResponse(requestObj);
|
||||
if (response) {
|
||||
peer.send(JSON.stringify(response));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('TypedRouter message handling error:', error);
|
||||
}
|
||||
} else {
|
||||
// Legacy mode: use onMessage hook
|
||||
const message = {
|
||||
type: typeof event.data === 'string' ? 'text' as const : 'binary' as const,
|
||||
text: typeof event.data === 'string' ? event.data : undefined,
|
||||
data: event.data instanceof Uint8Array ? event.data : undefined,
|
||||
size: typeof event.data === 'string' ? event.data.length : (event.data as ArrayBuffer).byteLength,
|
||||
};
|
||||
hooks.onMessage?.(peer, message);
|
||||
}
|
||||
};
|
||||
|
||||
socket.onclose = (event) => {
|
||||
// Unregister connection if typedRouter mode
|
||||
if (callbacks) {
|
||||
callbacks.onUnregister(peer.id);
|
||||
}
|
||||
hooks.onClose?.(peer, event.code, event.reason);
|
||||
};
|
||||
|
||||
@@ -121,12 +147,12 @@ export class DenoAdapter extends BaseAdapter {
|
||||
};
|
||||
}
|
||||
|
||||
private createWebSocketPeer(socket: WebSocket, request: Request): any {
|
||||
private createWebSocketPeer(socket: WebSocket, request: Request): IWebSocketPeer {
|
||||
const url = this.parseUrl(request);
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
url: url.pathname,
|
||||
get readyState() { return socket.readyState; },
|
||||
get readyState() { return socket.readyState as 0 | 1 | 2 | 3; },
|
||||
protocol: socket.protocol,
|
||||
extensions: socket.extensions,
|
||||
send: (data: string) => socket.send(data),
|
||||
@@ -134,8 +160,9 @@ export class DenoAdapter extends BaseAdapter {
|
||||
close: (code?: number, reason?: string) => socket.close(code, reason),
|
||||
ping: () => { /* Deno handles ping/pong automatically */ },
|
||||
terminate: () => socket.close(),
|
||||
context: {} as any, // Will be populated with IRequestContext
|
||||
context: {} as any,
|
||||
data: new Map(),
|
||||
tags: new Set<string>(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user