From 2e6bded9d01c5f7c52746a8351632ef22c83d5ae Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Sat, 10 Aug 2024 13:51:49 +0800 Subject: [PATCH 1/4] fix: typo of `Emojio` -> Emoji --- .../extends/{FetchEmojioLike.ts => FetchEmojiLike.ts} | 6 +++--- src/onebot/action/index.ts | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) rename src/onebot/action/extends/{FetchEmojioLike.ts => FetchEmojiLike.ts} (83%) diff --git a/src/onebot/action/extends/FetchEmojioLike.ts b/src/onebot/action/extends/FetchEmojiLike.ts similarity index 83% rename from src/onebot/action/extends/FetchEmojioLike.ts rename to src/onebot/action/extends/FetchEmojiLike.ts index 4ae82c28..03cb98d8 100644 --- a/src/onebot/action/extends/FetchEmojioLike.ts +++ b/src/onebot/action/extends/FetchEmojiLike.ts @@ -3,6 +3,7 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import BaseAction from '../BaseAction'; import { ActionName } from '../types'; import { MessageUnique } from '@/common/utils/MessageUnique'; + const SchemaData = { type: 'object', properties: { @@ -18,7 +19,7 @@ const SchemaData = { type Payload = FromSchema; -export class FetchEmojioLike extends BaseAction { +export class FetchEmojiLike extends BaseAction { actionName = ActionName.FetchEmojioLike; PayloadSchema = SchemaData; protected async _handle(payload: Payload) { @@ -26,7 +27,6 @@ export class FetchEmojioLike extends BaseAction { const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); if(!msgIdPeer) throw new Error('消息不存在'); const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0]; - const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count); - return ret; + return await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, payload.count); } } diff --git a/src/onebot/action/index.ts b/src/onebot/action/index.ts index 0d80862f..aeba84ef 100644 --- a/src/onebot/action/index.ts +++ b/src/onebot/action/index.ts @@ -35,7 +35,6 @@ import GetImage from './file/GetImage'; import GetRecord from './file/GetRecord'; import { GoCQHTTPMarkMsgAsRead, MarkAllMsgAsRead, MarkGroupMsgAsRead, MarkPrivateMsgAsRead } from './msg/MarkMsgAsRead'; import GoCQHTTPUploadGroupFile from './go-cqhttp/UploadGroupFile'; -import GetGroupAddRequest from '@/onebot/action/extends/GetGroupAddRequest'; import SetQQAvatar from '@/onebot/action/extends/SetQQAvatar'; import GoCQHTTPDownloadFile from './go-cqhttp/DownloadFile'; import GoCQHTTPGetGroupMsgHistory from './go-cqhttp/GetGroupMsgHistory'; @@ -73,13 +72,13 @@ import { GetProfileLike } from './extends/GetProfileLike'; import SetGroupHeader from './extends/SetGroupHeader'; import { FetchCustomFace } from './extends/FetchCustomFace'; import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile'; -import { FetchEmojioLike } from './extends/FetchEmojioLike'; +import { FetchEmojiLike } from './extends/FetchEmojiLike'; import { NapCatCore } from '@/core'; import { NapCatOneBot11Adapter } from '../main'; export function createActionMap(onebotContext: NapCatOneBot11Adapter, coreContext: NapCatCore) { const actionHandlers = [ - new FetchEmojioLike(onebotContext,coreContext), + new FetchEmojiLike(onebotContext,coreContext), new GetFile(onebotContext,coreContext), new SetSelfProfile(onebotContext,coreContext), new shareGroupEx(onebotContext,coreContext), From 704e5f7134b0a0f1f1c73c2e487f153f8c9d88bc Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Sat, 10 Aug 2024 13:53:24 +0800 Subject: [PATCH 2/4] fix: typo of `Emojio` -> Emoji --- src/onebot/action/extends/FetchEmojiLike.ts | 2 +- src/onebot/action/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/onebot/action/extends/FetchEmojiLike.ts b/src/onebot/action/extends/FetchEmojiLike.ts index 03cb98d8..f61cc5e5 100644 --- a/src/onebot/action/extends/FetchEmojiLike.ts +++ b/src/onebot/action/extends/FetchEmojiLike.ts @@ -20,7 +20,7 @@ const SchemaData = { type Payload = FromSchema; export class FetchEmojiLike extends BaseAction { - actionName = ActionName.FetchEmojioLike; + actionName = ActionName.FetchEmojiLike; PayloadSchema = SchemaData; protected async _handle(payload: Payload) { const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; diff --git a/src/onebot/action/types.ts b/src/onebot/action/types.ts index 408f933a..ce7d6f6d 100644 --- a/src/onebot/action/types.ts +++ b/src/onebot/action/types.ts @@ -104,5 +104,5 @@ export enum ActionName { FetchCustomFace = 'fetch_custom_face', GOCQHTTP_UploadPrivateFile = 'upload_private_file', TestApi01 = 'test_api_01', - FetchEmojioLike = 'fetch_emoji_like' + FetchEmojiLike = 'fetch_emoji_like' } From 33ef3e7d59c2a28482afe5c4fc0064b778596384 Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Sat, 10 Aug 2024 14:00:56 +0800 Subject: [PATCH 3/4] update: interface IOB11NetworkAdapter --- src/onebot/network/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/onebot/network/index.ts diff --git a/src/onebot/network/index.ts b/src/onebot/network/index.ts new file mode 100644 index 00000000..18d2840f --- /dev/null +++ b/src/onebot/network/index.ts @@ -0,0 +1,7 @@ +import BaseAction from '@/onebot/action/BaseAction'; +import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent'; + +export interface IOB11NetworkAdapter { + registerAction, P, R>(action: T): void; + onEvent(event: T): void; +} From 8060b1c753db7a741e14c1d955fc0d8dfa64d0f7 Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Sat, 10 Aug 2024 14:40:51 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20a=20framework=20of=20passive=20(?= =?UTF-8?q?=E6=AD=A3=E5=90=91)=20websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +- src/onebot/network/index.ts | 2 + src/onebot/network/passive-websocket.ts | 72 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 src/onebot/network/passive-websocket.ts diff --git a/package.json b/package.json index b598bd9e..7acf7d70 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@types/jest": "^29.5.12", "@types/node": "^22.0.0", "@types/qrcode-terminal": "^0.12.2", - "@types/ws": "^8.5.10", + "@types/ws": "^8.5.12", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", "eslint": "^8.57.0", @@ -46,6 +46,7 @@ }, "dependencies": { "ajv": "^8.13.0", + "async-mutex": "^0.5.0", "chalk": "^5.3.0", "commander": "^12.1.0", "cors": "^2.8.5", @@ -59,6 +60,6 @@ "qrcode-terminal": "^0.12.0", "silk-wasm": "^3.6.1", "strtok3": "8.0.1", - "ws": "^8.16.0" + "ws": "^8.18.0" } } diff --git a/src/onebot/network/index.ts b/src/onebot/network/index.ts index 18d2840f..673c4e4d 100644 --- a/src/onebot/network/index.ts +++ b/src/onebot/network/index.ts @@ -4,4 +4,6 @@ import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent'; export interface IOB11NetworkAdapter { registerAction, P, R>(action: T): void; onEvent(event: T): void; + open(): void | Promise; + close(): void | Promise; } diff --git a/src/onebot/network/passive-websocket.ts b/src/onebot/network/passive-websocket.ts new file mode 100644 index 00000000..da321a61 --- /dev/null +++ b/src/onebot/network/passive-websocket.ts @@ -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> = 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, P, R>(action: T) { + this.actionMap.set(action.actionName, action); + } + + onEvent(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(); + } +}