From cad33500d26cffbc781e9775d3c2c7da73cb8e6e Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Fri, 19 Apr 2024 13:58:02 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/server/src/feiyun.ts | 57 +++-------------------------------- packages/server/src/server.ts | 47 +++++++++++++++++++++-------- packages/server/src/socket.ts | 11 ++++--- 3 files changed, 45 insertions(+), 70 deletions(-) diff --git a/packages/server/src/feiyun.ts b/packages/server/src/feiyun.ts index f1a454a..05f2ca4 100644 --- a/packages/server/src/feiyun.ts +++ b/packages/server/src/feiyun.ts @@ -39,29 +39,7 @@ export class Feiyun { this.config = { ...this.config, ...config } } - listen(port?: number) { - // const wss = new WebSocketServer(this.config); - // wss.on('connection', (ws, request) => { - // ws.on('open', () => { - - // }); - // ws.on('message', () => { - - // }); - // ws.on('error', () => { - - // }); - // ws.on('close', () => { - - // }); - // }); - // wss.on('close', () => { - - // }); - - // wss.on('error', () => { - - // }); + listen() { this.server = new Server(this.config) this.server.start() this.server.handlerCallback = (client, data) => { @@ -87,13 +65,6 @@ export class Feiyun { console.log('server listen:', `ws://${this.config.host}:${this.config.port}`) } - // callback() { - // const ctx = new Context(); - // return (client, data) => { - - // } - // } - use(fn: FeiyunMiddleware) { this.middleware.push(fn) return this @@ -101,28 +72,8 @@ export class Feiyun { async responseHandler(ctx: Context) { if (ctx.response.data) { - this.server.reply(ctx.socket.socket, ctx.request.id, ctx.response.data) + ctx.socket.send(ctx.request.id, ctx.response.data); + // this.server.reply(ctx.socket.socket, ctx.request.id, ctx.response.data) } } -} - -// const app = new Feiyun(); -// app.use(async (ctx, next) => { -// const msg = JSON.parse(ctx.message); -// const [rid, route, req]: [number, string, any] = msg; - -// const handler = this.handlers.get(route); - -// ctx.response.body = await handler(); - -// if (!handler) { -// return; -// } - -// const res = await handler(req, client); - -// // 如果有返回值,那么直接回应 -// if (res) { -// this.reply(client.socket, rid, res); -// } -// }); +} \ No newline at end of file diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index f48dfe6..7ad72e5 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -21,7 +21,7 @@ export class Server { clients: Map = new Map() clientsFromServerWebSocket: Map = new Map(); - clientsFromUid: Map = new Map() + clientsFromUid: Map = new Map() /** * 配置 @@ -83,22 +83,19 @@ export class Server { * @param name * @param data */ - send(sokcet: ServerWebSocket, name: string | number, data: any) { - sokcet.send(JSON.stringify([1, name, data])) - } + // send(sokcet: Socket, 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) - + sendToUid(uid: number, name: string, data: any) { + const socket = this.getByUid(uid); if (!socket) { return false } - socket.send(name, data) - return true } @@ -106,10 +103,36 @@ export class Server { * 给客户端回复消息 * @param socket * @param id - * @param data + * @param data - 内容 + */ + reply(socket: Socket, id: number, data: any) { + socket.send(id, data) + } + + /** + * 绑定uid到连接上 + * @param uid + * @param socket + */ + bindUid(uid: number, socket: Socket) { + this.clientsFromUid.set(uid, socket); + } + + /** + * 获取用户连接 + * @param uid + * @returns + */ + getByUid(uid: number) { + return this.clientsFromUid.get(uid); + } + + /** + * 获取在线状态 */ - reply(socket: ServerWebSocket, id: number, data: any) { - this.send(socket, id, data) + isOnline(uid: number) { + const socket = this.getByUid(uid); + return socket?.socket.readyState === 1 } isDebug = false diff --git a/packages/server/src/socket.ts b/packages/server/src/socket.ts index b753ddf..8f79df6 100644 --- a/packages/server/src/socket.ts +++ b/packages/server/src/socket.ts @@ -15,22 +15,23 @@ export class Socket { this.data[name] = value } - private _uid?: number | string + private _uid?: number get uid() { return this._uid } - set uid(val) { this._uid = val if (this._uid !== undefined) { - this.server.clientsFromUid.set(this._uid, this) + this.server.bindUid(this._uid, this); } } /** * 发送消息 */ - send(name: string, data?: any) { - this.server.send(this.socket, name, data) + send(name: number, data?: any): void + send(name: string, data?: any): void + send(name: string | number, data?: any) { + this.socket.send(JSON.stringify([1, name, data])) } } From 101c042f35a59e63f4433d850b0a1ee9a1f2ab7c Mon Sep 17 00:00:00 2001 From: youxia <675567585@qq.com> Date: Thu, 27 Jun 2024 04:41:36 +0700 Subject: [PATCH 2/3] Tcp server --- packages/server/src/BaseServer.ts | 43 +++++++++++++++ packages/server/src/IServer.ts | 42 +++++++++++++++ packages/server/src/feiyun.ts | 11 ++-- packages/server/src/server.ts | 81 ++++++++++++++++------------ packages/server/src/socket.ts | 27 +++++++--- packages/server/src/tcp/TcpServer.ts | 43 +++++++++++++++ packages/server/src/ws.ts | 22 +++++--- 7 files changed, 215 insertions(+), 54 deletions(-) create mode 100644 packages/server/src/BaseServer.ts create mode 100644 packages/server/src/IServer.ts create mode 100644 packages/server/src/tcp/TcpServer.ts diff --git a/packages/server/src/BaseServer.ts b/packages/server/src/BaseServer.ts new file mode 100644 index 0000000..3c36da7 --- /dev/null +++ b/packages/server/src/BaseServer.ts @@ -0,0 +1,43 @@ +import { Socket } from "./socket"; + +export abstract class BaseServer { + sockets = new Map(); + clients = new Map(); + uidSocketIds = new Map() + + + handlerCallback?: ((client: Socket, data: string) => void) | undefined; + + bindUid(uid: number, socket: Socket): void { + this.uidSocketIds.set(uid, socket.id) + } + unbindUid(uid: number): void { + this.uidSocketIds.delete(uid) + } + + abstract send(socket: T, name: string | number, data: any): void; + + sendTo(uid: number, name: string, data: any): void { + const tcpSocket = this.clients.get(uid); + if (!tcpSocket) { + return; + } + this.send(tcpSocket, name, data) + } + sendToUid(uid: number, name: string, data: any): void { + const socketId = this.uidSocketIds.get(uid) + + if (!socketId) { + return; + } + this.sendTo(socketId, name, data) + } + reply(socketId: number, requestId: number, data: any): void { + const sws = this.clients.get(socketId); + if (!sws) { + return; + } + this.send(sws, requestId, data) + } + +} \ No newline at end of file diff --git a/packages/server/src/IServer.ts b/packages/server/src/IServer.ts new file mode 100644 index 0000000..b861159 --- /dev/null +++ b/packages/server/src/IServer.ts @@ -0,0 +1,42 @@ +import { Socket } from "./socket" + +export interface IServer { + + start(): void + + handlerCallback?: (client: Socket, data: string) => void + + /** + * 绑定uid + * @param uid + * @param socket + */ + bindUid(uid: number, socket: Socket): void + /** + * 解除用户绑定 + * @param uid + */ + unbindUid(uid: number): void + /** + * 给指定id发送消息 + * @param uid + * @param name + * @param data + */ + sendTo(uid: number, name: string, data: any): void + /** + * 给自定用户发送消息 + * @param uid + * @param name + * @param data + */ + sendToUid(uid: number, name: string, data: any): void + + /** + * 回复消息 + * @param id + * @param requestId + * @param data + */ + reply(id: number, requestId: number, data: any): void; +} \ No newline at end of file diff --git a/packages/server/src/feiyun.ts b/packages/server/src/feiyun.ts index 05f2ca4..23fb6bf 100644 --- a/packages/server/src/feiyun.ts +++ b/packages/server/src/feiyun.ts @@ -1,10 +1,12 @@ import type { Socket } from './socket' import { compose, type Middleware } from './compose' import { Server } from './server' +import { IServer } from './IServer' export interface ApplicationConfig { host: string port: number + customServer?: (config: ApplicationConfig) => IServer } export class Request { @@ -33,14 +35,16 @@ export class Feiyun { port: 3000, } - public server!: Server + public server!: IServer constructor(config: Partial = {}) { this.config = { ...this.config, ...config } } listen() { - this.server = new Server(this.config) + this.server = this.config.customServer ? this.config.customServer(this.config) : new Server({ + port: this.config.port + }) this.server.start() this.server.handlerCallback = (client, data) => { const ctx = new Context() @@ -72,8 +76,7 @@ export class Feiyun { async responseHandler(ctx: Context) { if (ctx.response.data) { - ctx.socket.send(ctx.request.id, ctx.response.data); - // this.server.reply(ctx.socket.socket, ctx.request.id, ctx.response.data) + this.server.reply(ctx.socket.id, ctx.request.id, ctx.response.data) } } } \ No newline at end of file diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 7ad72e5..2910b83 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -1,7 +1,7 @@ import { Socket } from './socket' -import { createWebsocketServer } from './ws' +import { SWS, WebSocketData, createWebsocketServer } from './ws' import { IWebsocketServer } from './IWebsocketServer' -import { ServerWebSocket } from 'bun' +import { IServer } from './IServer' type Handler = (msg: any, client: Socket) => Promise | any @@ -12,27 +12,23 @@ interface ServerConfig { /** * 服务器 */ -export class Server { +export class Server implements IServer { handlers = new Map() clientIndex: number = 0 - wss?: IWebsocketServer + wss?: IWebsocketServer - clients: Map = new Map() - clientsFromServerWebSocket: Map = new Map(); - clientsFromUid: Map = new Map() + clientsFromServerWebSocket: Map = new Map(); + + 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); } /** @@ -43,8 +39,9 @@ export class Server { port: this.config.port }); this.wss.open((ws) => { - const client = new Socket(++this.clientIndex, this, ws) - this.clients.set(this.clientIndex, client) + const client = new Socket(this) + ws.data.socketId = client.id; + this.clients.set(this.clientIndex, ws) this.clientsFromServerWebSocket.set(ws, client); }); this.wss.message((ws, data) => { @@ -77,36 +74,39 @@ export class Server { this.handlers.set(path, handler) } + unbindUid(uid: number): void { + this.clientsFromUid.delete(uid) + } + /** * 发送消息到客户端 * @param sokcet * @param name * @param data */ - // send(sokcet: Socket, name: string | number, data: any) { - // sokcet.send(JSON.stringify([1, name, data])) - // } + send(sokcet: SWS, name: string | number, data: any) { + sokcet.send(JSON.stringify([1, name, data])) + } - /** - * 发送消息到客户端(uid) - */ - sendToUid(uid: number, name: string, data: any) { - const socket = this.getByUid(uid); - if (!socket) { - return false + + sendTo(id: number, name: string, data: any): void { + const sws = this.clients.get(id); + if (!sws) { + return; } - socket.send(name, data) - return true + this.send(sws, name, data) } /** - * 给客户端回复消息 - * @param socket - * @param id - * @param data - 内容 + * 发送消息到客户端(uid) */ - reply(socket: Socket, id: number, data: any) { - socket.send(id, data) + sendToUid(uid: number, name: string, data: any) { + const socketId = this.clientsFromUid.get(uid) + + if (!socketId) { + return; + } + this.sendTo(socketId, name, data) } /** @@ -115,7 +115,7 @@ export class Server { * @param socket */ bindUid(uid: number, socket: Socket) { - this.clientsFromUid.set(uid, socket); + this.clientsFromUid.set(uid, socket.id); } /** @@ -131,8 +131,19 @@ export class Server { * 获取在线状态 */ isOnline(uid: number) { - const socket = this.getByUid(uid); - return socket?.socket.readyState === 1 + const socket = this.clients.get(uid); + return socket?.readyState === 1 + } + + /** + * 给客户端回复消息 + */ + reply(socketId: number, requestId: number, data: any) { + const sws = this.clients.get(socketId); + if (!sws) { + return; + } + this.send(sws, requestId, data) } isDebug = false diff --git a/packages/server/src/socket.ts b/packages/server/src/socket.ts index 8f79df6..4349cb7 100644 --- a/packages/server/src/socket.ts +++ b/packages/server/src/socket.ts @@ -1,8 +1,16 @@ -import { ServerWebSocket } from 'bun' -import type { Server } from './server' +import { IServer } from './IServer'; + +const createId = (() => { + let id = 0 + return () => { + return ++ id; + } +})(); export class Socket { - constructor(public id: number, public server: Server, public socket: ServerWebSocket) { + id = createId(); + + constructor(public server: IServer) { } @@ -29,9 +37,14 @@ export class Socket { /** * 发送消息 */ - send(name: number, data?: any): void - send(name: string, data?: any): void - send(name: string | number, data?: any) { - this.socket.send(JSON.stringify([1, name, data])) + send(name: string, data?: any) { + this.server.sendTo(this.id, name, data); + } + + /** + * 断开链接 + */ + close() { + } } diff --git a/packages/server/src/tcp/TcpServer.ts b/packages/server/src/tcp/TcpServer.ts new file mode 100644 index 0000000..91a19c6 --- /dev/null +++ b/packages/server/src/tcp/TcpServer.ts @@ -0,0 +1,43 @@ +import { BaseServer } from "../BaseServer"; +import { IServer } from "../IServer"; +import { Socket } from "../socket"; +import { Socket as TcpSocket } from "bun"; + +type SocketData = { socketId: number }; + +export class TcpServer extends BaseServer> implements IServer { + + constructor(public port: number) { + super(); + } + + start(): void { + Bun.listen({ + hostname: "0.0.0.0", + port: this.port, + socket: { + open: (socket) => { + const client = new Socket(this) + socket.data.socketId = client.id; + this.clients.set(client.id, socket) + this.sockets.set(client.id, client); + }, + data: (socket, data) => { + const client = this.sockets.get(socket.data.socketId)!; + try { + this.handlerCallback?.(client, data.toString()) + } catch (error) { + console.error(error) + } + }, + close: (socket) => { + this.sockets.delete(socket.data.socketId); + } + }, + }); + } + + send(socket: TcpSocket, name: string | number, data: any): void { + socket.write(JSON.stringify([1, name, data])); + } +} \ No newline at end of file diff --git a/packages/server/src/ws.ts b/packages/server/src/ws.ts index 718cf03..e96dcd4 100644 --- a/packages/server/src/ws.ts +++ b/packages/server/src/ws.ts @@ -1,11 +1,17 @@ import { ServerWebSocket } from "bun"; import { IWebsocketServer } from "./IWebsocketServer"; +export type WebSocketData = { + socketId: number +} + +export type SWS = ServerWebSocket; + const ALL = '_:world'; -export const createWebsocketServer = (options: { port?: number, timeout?: number } = {}): IWebsocketServer => { +export const createWebsocketServer = (options: { port?: number, timeout?: number } = {}): IWebsocketServer => { - const allTimeout: Map = new Map(); - const ping = (ws: ServerWebSocket) => { + const allTimeout: Map = new Map(); + const ping = (ws: SWS) => { if (!options.timeout || options.timeout < 0) { return } @@ -13,14 +19,14 @@ export const createWebsocketServer = (options: { port?: number, timeout?: number allTimeout.set(ws, setTimeout(ws.close, options.timeout)); } - const stopPing = (ws: ServerWebSocket) => { + const stopPing = (ws: SWS) => { 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; + let openHandler: (ws: SWS) => void; + let messageHandler: (ws: SWS, message: string | Buffer) => void; + let closeHandler: (ws: SWS) => void; const open = (handler: typeof openHandler) => { openHandler = handler; @@ -33,7 +39,7 @@ export const createWebsocketServer = (options: { port?: number, timeout?: number closeHandler = handler; } - Bun.serve({ + Bun.serve({ port: 3000, fetch(req, server) { if ( From 4f679c295217e556193e07a8a79da063fd47b335 Mon Sep 17 00:00:00 2001 From: youxia <675567585@qq.com> Date: Thu, 11 Jul 2024 02:14:44 +0700 Subject: [PATCH 3/3] tcp --- packages/feiyun/package.json | 2 +- packages/handler/package.json | 2 +- packages/server/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/feiyun/package.json b/packages/feiyun/package.json index 656c020..528fd41 100644 --- a/packages/feiyun/package.json +++ b/packages/feiyun/package.json @@ -1,7 +1,7 @@ { "name": "feiyun", "repository": "https://github.com/hxg2050/feiyun.git", - "version": "0.2.15", + "version": "0.2.16", "private": false, "type": "module", "main": "./src/index.ts", diff --git a/packages/handler/package.json b/packages/handler/package.json index 3e9df15..e853f2c 100644 --- a/packages/handler/package.json +++ b/packages/handler/package.json @@ -54,7 +54,7 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.11.19", - "feiyun": "^0.2.11", + "feiyun": "^0.2.16", "rollup": "^4.12.0", "rollup-plugin-ts": "^3.4.5", "tslib": "^2.6.2", diff --git a/packages/server/package.json b/packages/server/package.json index 2d87c11..38a23c9 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -2,7 +2,7 @@ "name": "@feiyun/server", "repository": "https://github.com/hxg2050/feiyun.git", "private": false, - "version": "0.0.6", + "version": "0.1.0", "type": "module", "main": "./src/index.ts", "engines": {