feat: a framework of passive (正向) websocket

This commit is contained in:
Wesley F. Young
2024-08-10 14:40:51 +08:00
parent 95615a868d
commit b39bc8828d
3 changed files with 77 additions and 2 deletions

View File

@@ -4,4 +4,6 @@ import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent';
export interface IOB11NetworkAdapter {
registerAction<T extends BaseAction<P, R>, P, R>(action: T): void;
onEvent<T extends OB11BaseEvent>(event: T): void;
open(): void | Promise<void>;
close(): void | Promise<void>;
}

View File

@@ -0,0 +1,72 @@
import { IOB11NetworkAdapter } from './index';
import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent';
import BaseAction from '@/onebot/action/BaseAction';
import { WebSocket, WebSocketServer } from 'ws';
import { Mutex } from 'async-mutex';
export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
wsServer: WebSocketServer;
wsClients: WebSocket[] = [];
wsClientsMutex = new Mutex();
isOpen: boolean = false;
hasBeenClosed: boolean = false;
private actionMap: Map<string, BaseAction<any, any>> = new Map();
constructor(ip: string, port: number, token: string) {
this.wsServer = new WebSocketServer({ port: port, host: ip });
this.wsServer.on('connection', async (wsClient) => {
if (!this.isOpen) {
wsClient.close();
return;
}
if (token) {
const incomingToken = wsClient.url.split('?')[1]?.split('=')[1];
if (incomingToken !== token) {
wsClient.close();
return;
}
}
wsClient.on('message', (message) => {
// TODO: extract action name and payload from the message, then call the corresponding action.
});
wsClient.once('close', () => {
this.wsClientsMutex.runExclusive(async () => {
const index = this.wsClients.indexOf(wsClient);
if (index !== -1) {
this.wsClients.splice(index, 1);
}
});
});
await this.wsClientsMutex.runExclusive(async () => {
this.wsClients.push(wsClient);
});
});
}
registerAction<T extends BaseAction<P, R>, P, R>(action: T) {
this.actionMap.set(action.actionName, action);
}
onEvent<T extends OB11BaseEvent>(event: T) {
this.wsClientsMutex.runExclusive(async () => {
this.wsClients.forEach((wsClient) => {
// wsClient.send(JSON.stringify(event));
// TODO: wrap the event, and send the wrapped to the client.
});
});
}
open() {
if (this.hasBeenClosed) {
throw new Error('Cannot open a closed WebSocket server');
}
this.isOpen = true;
}
async close() {
this.isOpen = false;
this.hasBeenClosed = true;
this.wsServer.close();
}
}