zero-remote
Version:
常连接网络
213 lines (205 loc) • 7.19 kB
text/typescript
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 })
}
}