UNPKG

zero-remote

Version:

常连接网络

213 lines (205 loc) 7.19 kB
import WebSocket from "ws" import ZeroDispatcher from "zero-dispatcher"; import { IChannel, ICSMessage, IPack, ISCMessage, jsonPack, ReportCode, ReturnReceiver, Sender } from "./IZeroRomeote"; /** * Ginger用户基础 * 访客 * 一个来访产出一个实例 * CSV: Client, Server, Value 客户端访问服务端的消息 * SCV: Client, Server, Value 服务端推送客户端的消息 */ export abstract class Visitor<CSV, SCV> { constructor(public channel: IChannel<SCV>, public server: ZeroRemote) { } abstract receive(body: CSV): void isClear: boolean = false clear(): void { this.isClear = true } start(): void { } kick() { this.clear(); this.channel.close(); } close() { this.channel.close() } } /** * 通信基础 */ export default class ZeroRemote<T = any> extends ZeroDispatcher<T>{ constructor(public ws: WebSocket.Server, callback: (channel: IChannel<any>, server: ZeroRemote) => Visitor<any, any>, public pack: IPack = jsonPack) { super() ws.on("connection", (socket, request) => { let user = callback({ close: () => { socket.close() }, send: (body) => { if (socket.readyState < 2) { let value = pack.stringify(body) if (value != null) { socket.send(value, (err) => { if (err) { // console.warn(err) // console.log(value) } }) } else { console.warn("ZeroServer: can't stringify for Json") } } else { console.log("ZeroServer: socket close") } } }, this) socket.on("message", (data) => { let body = this.pack.parse(data) if (body) { user.receive(body) } else { console.warn("ZeroServer: can't parse for data") console.warn("可能出现 粘包拆包") } }) socket.on("close", (code, reason) => { user.clear() }) user.start() }) } } /** * 添加 ping * 添加 callback * 添加 kick * 添加 router */ export class GameVisitor extends Visitor<ICSMessage, ISCMessage> { // protected routerPool: { [key: string]: ZeroDispatcher } = {} protected routerPool: { [key: string]: { [key: string]: Function } } = {} pingTime: number = 0; receive(body: ICSMessage): void { if (body.route == null) { if (body.data) { this.pingTime = body.data } this.channel.send({})//空对象当ping } else { if (body.cbs) { for (const key in body.cbs) { if (body.cbs.hasOwnProperty(key)) { const element = body.cbs[key]; body.data[key] = (...cbArgs: any[]) => { if (!this.isClear) { this.channel.send({ code: ReportCode.CALLBACK, ci: element, args: cbArgs } as any) } } } } } let back: Function | undefined = undefined if (body.index != null) { back = (isError: boolean, data?: any) => { if (!this.isClear) { this.channel.send({ code: ReportCode.CALLBACK, ci: body.index, args: [isError, data] } as any) } } } this.handle(body.route, body.key, body.data, back) } } handle(route: string, key: string, data: any, back: (Function | undefined)) { let router = this.routerPool[route] if (router != null) { let callback = router[key] if (callback != null) { let value: any try { value = callback(data) if (back != null) { if (value instanceof Promise) { value.then((valueThen) => { back!(true, valueThen) }).catch((error) => { if (error instanceof Error) { back!(false, error.message) } else { back!(false, error) } }) } else { back(true, value) } } } catch (error) { if (back != null) { back(false, error) } } } else { if (back != null) { back(false, route + " " + key + "这个接口没有实现") } } } else { if (back != null) { back(false, route + " 这个路由没有实现") } } } getReceiver<T>(route: string): ReturnReceiver<T> { return new Proxy<ReturnReceiver<T>>({} as any, { get: (target: any, p: string, receiver: any) => { return (callback: any) => { let router = this.routerPool[route] if (router == null) { router = {} this.routerPool[route] = router } router[p] = (data: any[]) => { if (Array.isArray(data)) { return callback(...data) } else { return callback(data) } } } } }) } getSender<T>(route: string): Sender<T> { return new Proxy<Sender<T>>({} as any, { get: (target: any, p: string, receiver: any) => { return (data: any) => { let sendInfo = { route: route, key: p, data: data } this.channel.send(sendInfo) } } }) } /** * @param data */ kick(data: any = 0) { this.channel.send({ code: ReportCode.KICK, data: data }) super.kick() } error(message: string) { this.channel.send({ code: ReportCode.ERROR, error: message }) } }