diff --git a/src/onebot/network/active-http.ts b/src/onebot/network/active-http.ts new file mode 100644 index 00000000..19d8f521 --- /dev/null +++ b/src/onebot/network/active-http.ts @@ -0,0 +1,43 @@ +import { IOB11NetworkAdapter } from '@/onebot/network/index'; +import BaseAction from '@/onebot/action/BaseAction'; +import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent'; + +export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter { + url: string; + private actionMap: Map> = new Map(); + + constructor(url: string) { + this.url = url; + } + + registerAction, P, R>(action: T) { + this.actionMap.set(action.actionName, action); + } + + onEvent(event: T) { + fetch(this.url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(event) + }) + .then(response => response.json()) + .then(data => { + console.log('Event sent successfully:', data); + }) + .catch(error => { + console.error('Failed to send event:', error); + }); + } + + async open() { + // HTTP adapter does not need to establish a persistent connection + console.log('HTTP adapter is ready to send events.'); + } + + close() { + // HTTP adapter does not need to close a persistent connection + console.log('HTTP adapter does not maintain a persistent connection.'); + } +} \ No newline at end of file diff --git a/src/onebot/network/passive-http.ts b/src/onebot/network/passive-http.ts new file mode 100644 index 00000000..960a4d60 --- /dev/null +++ b/src/onebot/network/passive-http.ts @@ -0,0 +1,75 @@ +import { IOB11NetworkAdapter } from './index'; +import { OB11BaseEvent } from '@/onebot/event/OB11BaseEvent'; +import BaseAction from '@/onebot/action/BaseAction'; +import { Mutex } from 'async-mutex'; +import express, { Express, Request, Response } from 'express'; +import http from 'http'; + +export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter { + private app: Express; + private server: http.Server; + private clients: { res: Response }[] = []; + private clientsMutex = new Mutex(); + private isOpen: boolean = false; + private hasBeenClosed: boolean = false; + private actionMap: Map> = new Map(); + + constructor(port: number) { + this.app = express(); + this.server = http.createServer(this.app); + + this.app.use(express.json()); + + this.app.post('/action', async (req: Request, res: Response) => { + if (!this.isOpen) { + res.status(503).send('Server is closed'); + return; + } + + const { actionName, payload } = req.body; + const action = this.actionMap.get(actionName); + if (action) { + const result = await action.handle(payload); + res.json(result); + } else { + res.status(404).send('Action not found'); + } + }); + + this.app.post('/event', (req: Request, res: Response) => { + this.clientsMutex.runExclusive(async () => { + this.clients.push({ res }); + }); + }); + + this.server.listen(port, () => { + console.log(`HTTP server listening on port ${port}`); + }); + } + + registerAction, P, R>(action: T) { + this.actionMap.set(action.actionName, action); + } + + onEvent(event: T) { + this.clientsMutex.runExclusive(async () => { + this.clients.forEach(({ res }) => { + res.json(event); + }); + this.clients = []; + }); + } + + open() { + if (this.hasBeenClosed) { + throw new Error('Cannot open a closed HTTP server'); + } + this.isOpen = true; + } + + async close() { + this.isOpen = false; + this.hasBeenClosed = true; + this.server.close(); + } +} \ No newline at end of file