diff --git a/bun.lockb b/bun.lockb index 47d2883..8dc5fb4 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 56323c2..927b30e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "feiyun", "private": false, - "version": "0.1.3", + "version": "0.2.0", "repository": "https://github.com/hxg2050/feiyun.git", "license": "MIT", "main": "./dist/index.cjs", @@ -25,6 +25,7 @@ }, "devDependencies": { "@rollup/plugin-typescript": "^11.1.3", + "@types/bun": "latest", "@types/jest": "^29.5.4", "@types/ws": "^8.5.5", "jest": "^29.7.0", diff --git a/src/server/GameSocket.ts b/src/server/GameSocket.ts deleted file mode 100644 index 7bc7996..0000000 --- a/src/server/GameSocket.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { GameSocketServer } from './GameSocketServer' -import type { WebSocket } from 'ws' - -export class GameSocket { - constructor(public id: number, public server: GameSocketServer, public socket: WebSocket) { - - } - - data: Record = {} - - /** - * 绑定数据 - */ - bind(name: string, value: any) { - this.data[name] = value - } - - private _uid?: number | string - get uid() { - return this._uid - } - - set uid(val) { - this._uid = val - if (this._uid !== undefined) { - this.server.clientsFromUid.set(this._uid, this) - } - } - - /** - * 发送消息 - */ - send(name: string, data?: any) { - this.server.send(this.socket, name, data) - } -} diff --git a/src/server/GameSocketServer.ts b/src/server/GameSocketServer.ts deleted file mode 100644 index 8e92dcf..0000000 --- a/src/server/GameSocketServer.ts +++ /dev/null @@ -1,175 +0,0 @@ -import type { IncomingMessage } from 'node:http' -import type WebSocket from 'ws' -import { WebSocketServer } from 'ws' -import { GameSocket } from './GameSocket' - -type Handler = (msg: any, client: GameSocket) => Promise | any - -interface ServerConfig { - port: number - timeout?: number -} -/** - * 服务器 - */ -export class GameSocketServer { - handlers = new Map() - - clientIndex: number = 0 - - wss?: WebSocketServer - - clients: Map = new Map() - clientsFromUid: Map = new Map() - - /** - * 配置 - * @param config 配置 - */ - constructor(private config: ServerConfig) { - // this.wss = new WebSocketServer(config); - // this.wss.on('connection', (socket, request) => { - // this.onConnection(socket, request); - // }); - // console.log('ws://127.0.0.1:' + config.port); - } - - /** - * 开始 - */ - start() { - this.wss = new WebSocketServer(this.config) - this.wss.on('connection', (socket, request) => { - this.onConnection(socket, request) - }) - console.log(`ws://127.0.0.1:${this.config.port}`) - } - - /** - * 当有新用户连接上来时 - * 处理心跳 - * @param socket - * @param request - */ - onConnection(socket: WebSocket, request: IncomingMessage) { - const client = new GameSocket(++this.clientIndex, this, socket) - this.clients.set(this.clientIndex, client) - let timeout: NodeJS.Timeout - const ping = () => { - if (!this.config.timeout || this.config.timeout < 0) { - return - } - console.log('刷新心跳') - clearTimeout(timeout) - timeout = setTimeout(close, this.config.timeout) - } - - const close = () => { - console.log('超时,断开链接') - socket.close() - } - this.config.timeout && ping() - - socket.on('message', (data) => { - const str = data.toString() - // console.log(str); - if (this.config.timeout && str === 'ping') { - ping() - return - } - this.onMessage(client, str) - }) - - socket.on('close', () => { - console.log('连接断开') - this.clients.delete(client.id) - if (client.uid !== undefined) { - this.clientsFromUid.delete(client.uid) - } - clearTimeout(timeout) - this.closeHandler && this.closeHandler(client) - }) - } - - async onMessage(client: GameSocket, data: string) { - try { - const msg = JSON.parse(data) - const [rid, route, req]: [number, string, any] = msg - - const handler = this.handlers.get(route) - - if (!handler) { - return - } - - const res = await handler(req, client) - - // 如果有返回值,那么直接回应 - if (res) { - this.reply(client.socket, rid, res) - } - } catch (error) { - console.error(error) - } - } - - private closeHandler?: (client: GameSocket) => void - onClose(callback: (client: GameSocket) => void) { - this.closeHandler = callback - } - - on(path: string, handler: Handler) { - this.handlers.set(path, handler) - } - - /** - * 发送消息到客户端 - * @param sokcet - * @param name - * @param data - */ - send(sokcet: WebSocket, name: string | number, data: any) { - sokcet.send(JSON.stringify([1, name, data])) - } - - /** - * 发送消息到客户端(uid) - */ - sendToUid(uid: string | number, name: string, data: any) { - const socket = this.clientsFromUid.get(uid) - - if (!socket) { - return false - } - - socket.send(name, data) - - return true - } - - /** - * 给客户端回复消息 - * @param socket - * @param id - * @param data - */ - reply(socket: WebSocket, id: number, data: any) { - // console.log('reply', data); - this.send(socket, id, data) - } - - isDebug = false - - doc?: string - - debug(isDebug: boolean, config: { - doc?: string - }) { - this.isDebug = isDebug - this.doc = config.doc - } - - // addHandler(allHandler: any[]) { - // const maps = mapRoute(allHandler); - // } -} diff --git a/src/server/IWebsocketServer.ts b/src/server/IWebsocketServer.ts new file mode 100644 index 0000000..c60cf76 --- /dev/null +++ b/src/server/IWebsocketServer.ts @@ -0,0 +1,7 @@ +import { ServerWebSocket } from "bun"; + +export interface IWebsocketServer { + open(handler: (ws: ServerWebSocket) => void): void; + message(handler: (ws: ServerWebSocket, message: string | Buffer) => void): void; + close(handler: (ws: ServerWebSocket) => void): void; +} \ No newline at end of file diff --git a/src/server/isBun.ts b/src/server/isBun.ts new file mode 100644 index 0000000..9051b9e --- /dev/null +++ b/src/server/isBun.ts @@ -0,0 +1,3 @@ +export const isBun = () => { + return typeof Bun !== 'undefined'; +} \ No newline at end of file diff --git a/src/server/server.ts b/src/server/server.ts index d9dbc3c..740f725 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1,10 +1,10 @@ -import type { IncomingMessage } from 'node:http' -import type WebSocket from 'ws' -import { WebSocketServer } from 'ws' import { Socket } from './socket' - +import { createWebsocketServer } from './ws' +import { IWebsocketServer } from './IWebSocketServer' +import { ServerWebSocket } from 'bun' type Handler = (msg: any, client: Socket) => Promise | any + interface ServerConfig { port: number timeout?: number @@ -17,9 +17,10 @@ export class Server { clientIndex: number = 0 - wss?: WebSocketServer + wss?: IWebsocketServer clients: Map = new Map() + clientsFromServerWebSocket: Map = new Map(); clientsFromUid: Map = new Map() /** @@ -38,79 +39,28 @@ export class Server { * 开始 */ start() { - this.wss = new WebSocketServer(this.config) - this.wss.on('connection', (socket, request) => { - this.onConnection(socket, request) - }) + this.wss = createWebsocketServer({ + port: this.config.port + }); + this.wss.open((ws) => { + const client = new Socket(++this.clientIndex, this, ws) + this.clients.set(this.clientIndex, client) + this.clientsFromServerWebSocket.set(ws, client); + }); + this.wss.message((ws, data) => { + const str = data.toString() + this.onMessage(this.clientsFromServerWebSocket.get(ws)!, str) + }); + this.wss.close((ws) => { + this.clientsFromServerWebSocket.delete(ws); + }); // console.log('ws://127.0.0.1:' + this.config.port); } - /** - * 当有新用户连接上来时 - * 处理心跳 - * @param socket - * @param request - */ - onConnection(socket: WebSocket, request: IncomingMessage) { - const client = new Socket(++this.clientIndex, this, socket) - this.clients.set(this.clientIndex, client) - let timeout: NodeJS.Timeout - const ping = () => { - if (!this.config.timeout || this.config.timeout < 0) { - return - } - console.log('刷新心跳') - clearTimeout(timeout) - timeout = setTimeout(close, this.config.timeout) - } - - const close = () => { - console.log('超时,断开链接') - socket.close() - } - this.config.timeout && ping() - - socket.on('message', (data) => { - const str = data.toString() - // console.log(str); - if (str === 'ping') { - if (this.config.timeout) { - ping() - } - return - } - this.onMessage(client, str) - }) - - socket.on('close', () => { - console.log('连接断开') - this.clients.delete(client.id) - if (client.uid !== undefined) { - this.clientsFromUid.delete(client.uid) - } - clearTimeout(timeout) - this.closeHandler && this.closeHandler(client) - }) - } async onMessage(client: Socket, data: string) { try { this.handlerCallback?.(client, data) - // const msg = JSON.parse(data); - // const [rid, route, req]: [number, string, any] = msg; - - // const handler = this.handlers.get(route); - - // if (!handler) { - // return; - // } - - // const res = await handler(req, client); - - // // 如果有返回值,那么直接回应 - // if (res) { - // this.reply(client.socket, rid, res); - // } } catch (error) { console.error(error) } @@ -133,7 +83,7 @@ export class Server { * @param name * @param data */ - send(sokcet: WebSocket, name: string | number, data: any) { + send(sokcet: ServerWebSocket, name: string | number, data: any) { sokcet.send(JSON.stringify([1, name, data])) } @@ -158,8 +108,7 @@ export class Server { * @param id * @param data */ - reply(socket: WebSocket, id: number, data: any) { - // console.log('reply', data); + reply(socket: ServerWebSocket, id: number, data: any) { this.send(socket, id, data) } @@ -173,8 +122,4 @@ export class Server { this.isDebug = isDebug this.doc = config.doc } - - // addHandler(allHandler: any[]) { - // const maps = mapRoute(allHandler); - // } } diff --git a/src/server/socket.ts b/src/server/socket.ts index 22ee17e..b753ddf 100644 --- a/src/server/socket.ts +++ b/src/server/socket.ts @@ -1,8 +1,8 @@ +import { ServerWebSocket } from 'bun' import type { Server } from './server' -import type { WebSocket } from 'ws' export class Socket { - constructor(public id: number, public server: Server, public socket: WebSocket) { + constructor(public id: number, public server: Server, public socket: ServerWebSocket) { } diff --git a/src/server/ws.ts b/src/server/ws.ts new file mode 100644 index 0000000..0eb997d --- /dev/null +++ b/src/server/ws.ts @@ -0,0 +1,74 @@ +import { ServerWebSocket } from "bun"; +import { IWebsocketServer } from "./IWebSocketServer"; + +const ALL = '_:world'; +export const createWebsocketServer = (options: {port?: number, timeout?: number} = {}): IWebsocketServer => { + + const allTimeout: Map = new Map(); + const ping = (ws: ServerWebSocket) => { + if (!options.timeout || options.timeout < 0) { + return + } + clearTimeout(allTimeout.get(ws)); + allTimeout.set(ws, setTimeout(ws.close, options.timeout)); + } + + const stopPing = (ws: ServerWebSocket) => { + clearTimeout(allTimeout.get(ws)); + allTimeout.delete(ws); + } + + let openHandler: (ws: ServerWebSocket) => void; + let messageHandler: (ws: ServerWebSocket, message: string | Buffer) => void; + let closeHandler: (ws: ServerWebSocket) => void; + + const open = (handler: typeof openHandler) => { + openHandler = handler; + } + const message = (handler: typeof messageHandler) => { + messageHandler = handler; + } + + const close = (handler: typeof closeHandler) => { + closeHandler = handler; + } + + Bun.serve({ + port: 3000, + fetch(req, server) { + if ( + server.upgrade(req, { + data: { + }, + }) + ) + return; + + return new Response("Error"); + }, + websocket: { + open(ws) { + ws.subscribe(ALL); + options.timeout && ping(ws); + openHandler && openHandler(ws); + }, + message(ws, message) { + message === 'ping' && options.timeout && ping(ws); + messageHandler && messageHandler(ws, message); + }, + close(ws) { + ws.unsubscribe(ALL); + options.timeout && stopPing(ws); + closeHandler && closeHandler(ws); + }, + perMessageDeflate: false, + publishToSelf: true, + }, + }); + + return { + open, + message, + close + } +} \ No newline at end of file