zero-remote
Advanced tools
| "use strict"; | ||
| /** | ||
| * 数据序列化标准 | ||
| */ | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ReportCode = exports.jsonPack = void 0; | ||
| /** | ||
| * Json序列化方案 | ||
| */ | ||
| exports.jsonPack = { | ||
| parse: (value) => { | ||
| try { | ||
| return JSON.parse(value); | ||
| } | ||
| catch (error) { | ||
| return null; | ||
| } | ||
| }, | ||
| stringify: (value) => { | ||
| try { | ||
| return JSON.stringify(value); | ||
| } | ||
| catch (error) { | ||
| return null; | ||
| } | ||
| } | ||
| }; | ||
| var ReportCode; | ||
| (function (ReportCode) { | ||
| ReportCode[ReportCode["CALLBACK"] = 50] = "CALLBACK"; | ||
| ReportCode[ReportCode["KICK"] = 10] = "KICK"; | ||
| ReportCode[ReportCode["ERROR"] = 5] = "ERROR"; | ||
| })(ReportCode = exports.ReportCode || (exports.ReportCode = {})); |
| /** | ||
| * 数据序列化标准 | ||
| */ | ||
| export interface IPack { | ||
| stringify(value: any): any | null; | ||
| parse(value: any): any | null; | ||
| } | ||
| /** | ||
| * 数据通信标准 | ||
| */ | ||
| export interface IChannel<T> { | ||
| close(): void; | ||
| send(body: T): void; | ||
| } | ||
| /** | ||
| * Json序列化方案 | ||
| */ | ||
| export let jsonPack: IPack = { | ||
| parse: (value) => { | ||
| try { | ||
| return JSON.parse(value) | ||
| } catch (error) { | ||
| return null | ||
| } | ||
| }, | ||
| stringify: (value) => { | ||
| try { | ||
| return JSON.stringify(value) | ||
| } catch (error) { | ||
| return null | ||
| } | ||
| } | ||
| } | ||
| export enum ReportCode { | ||
| CALLBACK = 50, | ||
| KICK = 10,//踢人 | ||
| ERROR = 5,//踢人 | ||
| } | ||
| export interface ISCMessage { | ||
| code?: ReportCode,//空为常规,成功 | ||
| route?: string,//路由号 | ||
| key?: string, //二级路由 | ||
| data?: any//数据 | ||
| error?: string//错误消息 | ||
| ci?: number | ||
| args?: any[]//回调参数 | ||
| } | ||
| export interface ICSMessage { | ||
| route: string,//路由号 | ||
| key: string, //二级路由 | ||
| data: any//数据 | ||
| cbs?: { [key: string]: number }//回调 只支持发送有回调 | ||
| index?: number//标准回调 | ||
| } | ||
| type Parameters<T> = T extends (...args: infer P) => any ? P : never; | ||
| type ReturnType<T> = T extends (...args: any) => infer R ? R : any; | ||
| export type Sender<T> = { [K in keyof T]: T[K] } | ||
| export type PromiseSender<T> = { [K in keyof T]: (...value: Parameters<T[K]>) => Promise<ReturnType<T[K]>> } | ||
| export type Receiver<T> = { [K in keyof T]: (callback: (...value: Parameters<T[K]>) => void) => void } | ||
| export type ReturnReceiver<T> = { [K in keyof T]: (callback: (...value: Parameters<T[K]>) => Promise<ReturnType<T[K]>>) => void } |
+20
-336
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ZeroRemoteClient = exports.GameVisitor = exports.LiteStack = exports.ReportCode = exports.jsonPack = exports.Visitor = void 0; | ||
| const ws_1 = __importDefault(require("ws")); | ||
| exports.GameVisitor = exports.Visitor = void 0; | ||
| const zero_mvc_1 = require("zero-mvc"); | ||
| const IZeroRomeote_1 = require("./IZeroRomeote"); | ||
| /** | ||
@@ -35,77 +32,6 @@ * Ginger用户基础 | ||
| /** | ||
| * Json序列化方案 | ||
| */ | ||
| exports.jsonPack = { | ||
| parse: (value) => { | ||
| try { | ||
| return JSON.parse(value); | ||
| } | ||
| catch (error) { | ||
| return null; | ||
| } | ||
| }, | ||
| stringify: (value) => { | ||
| try { | ||
| return JSON.stringify(value); | ||
| } | ||
| catch (error) { | ||
| return null; | ||
| } | ||
| } | ||
| }; | ||
| var ReportCode; | ||
| (function (ReportCode) { | ||
| ReportCode[ReportCode["CALLBACK"] = 50] = "CALLBACK"; | ||
| ReportCode[ReportCode["KICK"] = 10] = "KICK"; | ||
| ReportCode[ReportCode["ERROR"] = 5] = "ERROR"; | ||
| })(ReportCode = exports.ReportCode || (exports.ReportCode = {})); | ||
| /** | ||
| * 清洁型堆栈 | ||
| */ | ||
| class LiteStack { | ||
| constructor() { | ||
| this.pool = {}; | ||
| this.index = 0; | ||
| this.size = 0; | ||
| this.maxCount = 100; | ||
| } | ||
| push(item) { | ||
| this.index++; | ||
| this.size++; | ||
| this.pool[this.index] = item; | ||
| return this.index; | ||
| } | ||
| pull(index) { | ||
| let item = this.pool[index]; | ||
| if (item != null) { | ||
| delete this.pool[index]; | ||
| this.size--; | ||
| } | ||
| return item; | ||
| } | ||
| clear(keepLength) { | ||
| if (this.size > keepLength) { | ||
| let delLen = this.size - keepLength; | ||
| for (const key in this.pool) { | ||
| if (delLen > 0) { | ||
| delete this.pool[key]; | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| delLen--; | ||
| } | ||
| } | ||
| this.size = keepLength; | ||
| } | ||
| gc() { | ||
| this.clear(this.maxCount); | ||
| } | ||
| } | ||
| exports.LiteStack = LiteStack; | ||
| /** | ||
| * 通信基础 | ||
| */ | ||
| class ZeroRemote extends zero_mvc_1.ZeroDispatcher { | ||
| constructor(ws, callback, pack = exports.jsonPack) { | ||
| constructor(ws, callback, pack = IZeroRomeote_1.jsonPack) { | ||
| super(); | ||
@@ -125,4 +51,4 @@ this.ws = ws; | ||
| if (err) { | ||
| console.warn(err); | ||
| console.log(value); | ||
| // console.warn(err) | ||
| // console.log(value) | ||
| } | ||
@@ -169,5 +95,9 @@ }); | ||
| this.routerPool = {}; | ||
| this.pingTime = 0; | ||
| } | ||
| receive(body) { | ||
| if (body.route == null) { | ||
| if (body.data) { | ||
| this.pingTime = body.data; | ||
| } | ||
| this.channel.send({}); //空对象当ping | ||
@@ -183,3 +113,3 @@ } | ||
| this.channel.send({ | ||
| code: ReportCode.CALLBACK, | ||
| code: IZeroRomeote_1.ReportCode.CALLBACK, | ||
| ci: element, | ||
@@ -198,3 +128,3 @@ args: cbArgs | ||
| this.channel.send({ | ||
| code: ReportCode.CALLBACK, | ||
| code: IZeroRomeote_1.ReportCode.CALLBACK, | ||
| ci: body.index, | ||
@@ -222,3 +152,8 @@ args: [isError, data] | ||
| }).catch((error) => { | ||
| back(false, error); | ||
| if (error instanceof Error) { | ||
| back(false, error.message); | ||
| } | ||
| else { | ||
| back(false, error); | ||
| } | ||
| }); | ||
@@ -245,3 +180,3 @@ } | ||
| if (back != null) { | ||
| back(false, "这个路由没有实现"); | ||
| back(false, route + " 这个路由没有实现"); | ||
| } | ||
@@ -279,260 +214,9 @@ } | ||
| kick() { | ||
| this.channel.send({ code: ReportCode.KICK }); | ||
| this.channel.send({ code: IZeroRomeote_1.ReportCode.KICK }); | ||
| super.kick(); | ||
| } | ||
| error(message) { | ||
| this.channel.send({ code: ReportCode.ERROR, error: message }); | ||
| this.channel.send({ code: IZeroRomeote_1.ReportCode.ERROR, error: message }); | ||
| } | ||
| } | ||
| exports.GameVisitor = GameVisitor; | ||
| /** | ||
| * 错误错误会弹窗 | ||
| * 重连多次后会弹窗 | ||
| */ | ||
| /** | ||
| * 与后端协议 | ||
| * 所有数据以IMessage接收和发送 | ||
| * 只支持一级属性是个回调函数 | ||
| */ | ||
| class ZeroRemoteClient extends zero_mvc_1.ZeroDispatcher { | ||
| constructor(url) { | ||
| super(); | ||
| this.url = url; | ||
| this.relinkMaxCount = 3; | ||
| this.relinkTime = 2000; | ||
| /** | ||
| * 回调函数缓存个数 | ||
| */ | ||
| this.callBackMaxIndex = 1000; | ||
| this.outTime = 1; //整秒 | ||
| this.heartbeatTime = 5; //整秒=5 | ||
| this.pack = exports.jsonPack; | ||
| this.isOpen = false; | ||
| this.isBusy = false; | ||
| this.isRelink = true; | ||
| this.relinkCount = 0; | ||
| this.router = new zero_mvc_1.ZeroDispatcher(); | ||
| this.callbackPool = {}; | ||
| this.ci = 0; | ||
| this.pingIndex = 0; | ||
| this._mask = false; | ||
| setInterval(() => { | ||
| if (this.isOpen) { | ||
| if (this.pingIndex == this.heartbeatTime + this.outTime) { | ||
| this.mask = true; | ||
| } | ||
| else if (this.pingIndex == this.heartbeatTime) { | ||
| this.ws.send(this.pack.stringify({})); | ||
| } | ||
| this.pingIndex++; | ||
| } | ||
| }, 1000); | ||
| } | ||
| get mask() { | ||
| return this._mask; | ||
| } | ||
| set mask(value) { | ||
| if (this._mask != value) { | ||
| this._mask = value; | ||
| if (this._mask) { | ||
| // this.showMask() | ||
| this.emit("showMask"); | ||
| } | ||
| else { | ||
| // this.hideMask() | ||
| this.emit("hideMask"); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * 本条结构协议 | ||
| * @param route 要发送的路由名 | ||
| * @returns | ||
| */ | ||
| getSender(route) { | ||
| return new Proxy({}, { | ||
| get: (target, p, receiver) => { | ||
| return (data) => { | ||
| return new Promise((resolve, reject) => { | ||
| this.send(route, p, data, (isError, value) => { | ||
| if (isError) { | ||
| resolve(value); | ||
| } | ||
| else { | ||
| reject(value); | ||
| this.emit("error", value); | ||
| } | ||
| }); | ||
| }); | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| getReceiver(r) { | ||
| return new Proxy({}, { | ||
| get: (target, p, receiver) => { | ||
| return (data) => { | ||
| this.receive(r, p, data); | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| send(route, key, data, callback) { | ||
| if (this.isOpen) { | ||
| if (!this.mask) { | ||
| let cbs = undefined; | ||
| for (const key in data) { | ||
| if (data.hasOwnProperty(key)) { | ||
| const element = data[key]; | ||
| if (typeof element == "function") { | ||
| this.ci++; | ||
| delete this.callbackPool[this.ci - this.callBackMaxIndex]; | ||
| this.callbackPool[this.ci] = element; | ||
| if (cbs == null) { | ||
| cbs = {}; | ||
| } | ||
| cbs[key] = this.ci; | ||
| } | ||
| } | ||
| } | ||
| let index = undefined; | ||
| if (callback != null) { | ||
| this.ci++; | ||
| delete this.callbackPool[this.ci - this.callBackMaxIndex]; | ||
| index = this.ci; | ||
| this.callbackPool[this.ci] = callback; | ||
| } | ||
| this.ws.send(this.pack.stringify({ route: route, key: key, data: data, cbs: cbs, index: index })); | ||
| } | ||
| else { | ||
| // console.log("弱网环境,send信息被忽略" + route) | ||
| callback(false, "弱网环境,send信息被忽略"); | ||
| } | ||
| } | ||
| else { | ||
| // console.log("游戏服务器未连接,send信息被忽略" + route) | ||
| callback(false, "服务器未连接,send信息被忽略"); | ||
| } | ||
| } | ||
| receive(route, key, callback) { | ||
| this.router.on(route + "." + key, callback); | ||
| } | ||
| reLink() { | ||
| if (this.relinkCount < this.relinkMaxCount) { | ||
| this.relinkTimeOut = setTimeout(() => { | ||
| this.relinkTimeOut == null; | ||
| this.relinkCount++; | ||
| this.link(); | ||
| }, this.relinkTime); | ||
| } | ||
| else { | ||
| this.relinkCount = 0; | ||
| this.emit("popup"); | ||
| } | ||
| } | ||
| message(value) { | ||
| let obj; | ||
| try { | ||
| obj = this.pack.parse(value); | ||
| } | ||
| catch (_a) { | ||
| throw new Error("服务器数据无法序列化"); | ||
| } | ||
| this.pong(); | ||
| if (obj.code == null) { | ||
| if (obj.route != null) { | ||
| if (obj.key == null) { | ||
| throw new Error("服务器数据出错"); | ||
| } | ||
| else { | ||
| this.router.emit(obj.route + "." + obj.key, obj.data); | ||
| } | ||
| } | ||
| } | ||
| else if (obj.code == ReportCode.CALLBACK) { | ||
| if (obj.ci != null) { | ||
| let method = this.callbackPool[obj.ci]; | ||
| if (method) { | ||
| method.apply(this, obj.args); | ||
| delete this.callbackPool[obj.ci]; | ||
| } | ||
| } | ||
| } | ||
| else if (obj.code == ReportCode.KICK) { | ||
| this.close(); | ||
| } | ||
| else { | ||
| this.emit("error", obj.error); | ||
| } | ||
| } | ||
| pong() { | ||
| this.emit("heartbeat"); | ||
| this.pingIndex = 0; | ||
| this.mask = false; | ||
| } | ||
| /** | ||
| * 这个callback 在重连里不会触发 | ||
| * 如需要触发 请使用 on("linked") | ||
| * @param callback | ||
| */ | ||
| link(callback) { | ||
| this.isRelink = true; | ||
| if (this.url == "" || this.url == null) { | ||
| throw new Error("服务器地址为空"); | ||
| } | ||
| else { | ||
| if (this.isBusy) { | ||
| throw new Error("重复连接服务"); | ||
| } | ||
| else { | ||
| this.ws = new ws_1.default(this.url); | ||
| this.isBusy = true; | ||
| this.emit("linking"); | ||
| this.ws.onerror = () => { | ||
| this.emit("error", "网络出错"); | ||
| }; | ||
| this.ws.onopen = () => { | ||
| this.mask = false; | ||
| this.relinkCount = 0; | ||
| this.isOpen = true; | ||
| this.emit("linked"); | ||
| if (callback) { | ||
| callback(); | ||
| } | ||
| }; | ||
| this.ws.onclose = () => { | ||
| this.mask = true; | ||
| this.isOpen = false; | ||
| this.isBusy = false; | ||
| this.emit("suspend"); | ||
| for (const key in this.callbackPool) { | ||
| if (Object.prototype.hasOwnProperty.call(this.callbackPool, key)) { | ||
| const element = this.callbackPool[key]; | ||
| element(false, "网络断开"); | ||
| delete this.callbackPool[key]; | ||
| } | ||
| } | ||
| if (this.isRelink) { | ||
| this.reLink(); | ||
| } | ||
| else { | ||
| this.emit("stop"); | ||
| } | ||
| }; | ||
| this.ws.onmessage = (evt) => { | ||
| this.message(evt.data.toString()); | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| close() { | ||
| if (this.relinkTimeOut) { | ||
| clearTimeout(this.relinkTimeOut); | ||
| this.relinkTimeOut == null; | ||
| } | ||
| this.isRelink = false; | ||
| this.isOpen = false; | ||
| this.ws.close(); | ||
| } | ||
| } | ||
| exports.ZeroRemoteClient = ZeroRemoteClient; |
+13
-400
@@ -1,12 +0,5 @@ | ||
| import WebSocket from "ws" | ||
| import { ZeroDispatcher } from "zero-mvc"; | ||
| import { IChannel, ICSMessage, IPack, ISCMessage, jsonPack, ReportCode, ReturnReceiver, Sender } from "./IZeroRomeote"; | ||
| /** | ||
| * 数据通信标准 | ||
| */ | ||
| export interface IChannel<T> { | ||
| close(): void; | ||
| send(body: T): void; | ||
| } | ||
@@ -39,98 +32,2 @@ /** | ||
| /** | ||
| * 数据序列化标准 | ||
| */ | ||
| export interface IPack { | ||
| stringify(value: any): any | null; | ||
| parse(value: any): any | null; | ||
| } | ||
| /** | ||
| * Json序列化方案 | ||
| */ | ||
| export let jsonPack: IPack = { | ||
| parse: (value) => { | ||
| try { | ||
| return JSON.parse(value) | ||
| } catch (error) { | ||
| return null | ||
| } | ||
| }, | ||
| stringify: (value) => { | ||
| try { | ||
| return JSON.stringify(value) | ||
| } catch (error) { | ||
| return null | ||
| } | ||
| } | ||
| } | ||
| export enum ReportCode { | ||
| CALLBACK = 50, | ||
| KICK = 10,//踢人 | ||
| ERROR = 5,//踢人 | ||
| } | ||
| export interface ISCMessage { | ||
| code?: ReportCode,//空为常规,成功 | ||
| route?: string,//路由号 | ||
| key?: string, //二级路由 | ||
| data?: any//数据 | ||
| error?: string//错误消息 | ||
| ci?: number | ||
| args?: any[]//回调参数 | ||
| } | ||
| export interface ICSMessage { | ||
| route: string,//路由号 | ||
| key: string, //二级路由 | ||
| data: any//数据 | ||
| cbs?: { [key: string]: number }//回调 只支持发送有回调 | ||
| index?: number//标准回调 | ||
| } | ||
| /** | ||
| * 清洁型堆栈 | ||
| */ | ||
| export class LiteStack<T> { | ||
| private pool: { [key: number]: T; } = {}; | ||
| private index: number = 0; | ||
| public size: number = 0; | ||
| public maxCount: number = 100 | ||
| push(item: T): number { | ||
| this.index++; | ||
| this.size++; | ||
| this.pool[this.index] = item; | ||
| return this.index; | ||
| } | ||
| pull(index: number): T | null { | ||
| let item = this.pool[index]; | ||
| if (item != null) { | ||
| delete this.pool[index]; | ||
| this.size--; | ||
| } | ||
| return item; | ||
| } | ||
| clear(keepLength: number) { | ||
| if (this.size > keepLength) { | ||
| let delLen = this.size - keepLength; | ||
| for (const key in this.pool) { | ||
| if (delLen > 0) { | ||
| delete this.pool[key]; | ||
| } else { | ||
| break; | ||
| } | ||
| delLen--; | ||
| } | ||
| } | ||
| this.size = keepLength; | ||
| } | ||
| gc() { | ||
| this.clear(this.maxCount) | ||
| } | ||
| } | ||
| /** | ||
| * 通信基础 | ||
@@ -153,4 +50,4 @@ */ | ||
| if (err) { | ||
| console.warn(err) | ||
| console.log(value) | ||
| // console.warn(err) | ||
| // console.log(value) | ||
| } | ||
@@ -194,5 +91,9 @@ }) | ||
| 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 | ||
@@ -244,3 +145,7 @@ } else { | ||
| }).catch((error) => { | ||
| back!(false, error) | ||
| if (error instanceof Error) { | ||
| back!(false, error.message) | ||
| } else { | ||
| back!(false, error) | ||
| } | ||
| }) | ||
@@ -263,3 +168,3 @@ } else { | ||
| if (back != null) { | ||
| back(false, "这个路由没有实现") | ||
| back(false, route + " 这个路由没有实现") | ||
| } | ||
@@ -304,293 +209,1 @@ } | ||
| } | ||
| type Parameters<T> = T extends (...args: infer P) => any ? P : never; | ||
| type ReturnType<T> = T extends (...args: any) => infer R ? R : any; | ||
| export type Sender<T> = { [K in keyof T]: T[K] } | ||
| export type PromiseSender<T> = { [K in keyof T]: (...value: Parameters<T[K]>) => Promise<ReturnType<T[K]>> } | ||
| export type Receiver<T> = { [K in keyof T]: (callback: (...value: Parameters<T[K]>) => void) => void } | ||
| export type ReturnReceiver<T> = { [K in keyof T]: (callback: (...value: Parameters<T[K]>) => Promise<ReturnType<T[K]>>) => void } | ||
| /** | ||
| * 错误错误会弹窗 | ||
| * 重连多次后会弹窗 | ||
| */ | ||
| /** | ||
| * 与后端协议 | ||
| * 所有数据以IMessage接收和发送 | ||
| * 只支持一级属性是个回调函数 | ||
| */ | ||
| export class ZeroRemoteClient extends ZeroDispatcher<{ | ||
| /** | ||
| * 消息阻塞 | ||
| */ | ||
| showMask: [] | ||
| /** | ||
| * 阻塞后收到消息 | ||
| */ | ||
| hideMask: [] | ||
| /** | ||
| * 主动错误 | ||
| * 用于debug | ||
| */ | ||
| error: [string?] | ||
| /** | ||
| * 重连提示 | ||
| */ | ||
| popup: [] | ||
| /** | ||
| * 心跳 | ||
| */ | ||
| heartbeat: [] | ||
| /** | ||
| * 开始连接 | ||
| */ | ||
| linking: [] | ||
| /** | ||
| * 连接完成 | ||
| */ | ||
| linked: [] | ||
| /** | ||
| * 连接中断 | ||
| */ | ||
| suspend: [] | ||
| /** | ||
| * 连接结束 | ||
| */ | ||
| stop: [] | ||
| }> { | ||
| relinkMaxCount: number = 3 | ||
| relinkTime: number = 2000 | ||
| /** | ||
| * 回调函数缓存个数 | ||
| */ | ||
| callBackMaxIndex: number = 1000 | ||
| outTime: number = 1;//整秒 | ||
| heartbeatTime: number = 5;//整秒=5 | ||
| public pack: IPack = jsonPack | ||
| isOpen = false | ||
| isBusy = false | ||
| private isRelink: boolean = true | ||
| private relinkCount: number = 0 | ||
| protected ws!: WebSocket; | ||
| protected router: ZeroDispatcher<any> = new ZeroDispatcher(); | ||
| protected callbackPool: { [key: number]: Function } = {} | ||
| private ci: number = 0 | ||
| private pingIndex: number = 0 | ||
| private _mask: boolean = false | ||
| relinkTimeOut?: NodeJS.Timeout; | ||
| public get mask(): boolean { | ||
| return this._mask | ||
| } | ||
| public set mask(value: boolean) { | ||
| if (this._mask != value) { | ||
| this._mask = value | ||
| if (this._mask) { | ||
| // this.showMask() | ||
| this.emit("showMask") | ||
| } else { | ||
| // this.hideMask() | ||
| this.emit("hideMask") | ||
| } | ||
| } | ||
| } | ||
| constructor(public url: string) { | ||
| super() | ||
| setInterval(() => { | ||
| if (this.isOpen) { | ||
| if (this.pingIndex == this.heartbeatTime + this.outTime) { | ||
| this.mask = true | ||
| } else if (this.pingIndex == this.heartbeatTime) { | ||
| this.ws.send(this.pack.stringify({})) | ||
| } | ||
| this.pingIndex++ | ||
| } | ||
| }, 1000) | ||
| } | ||
| /** | ||
| * 本条结构协议 | ||
| * @param route 要发送的路由名 | ||
| * @returns | ||
| */ | ||
| getSender<T>(route: string): PromiseSender<T> { | ||
| return new Proxy<PromiseSender<T>>({} as any, { | ||
| get: (target: any, p: string, receiver: any) => { | ||
| return (data: any) => { | ||
| return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { | ||
| this.send(route, p, data, (isError: boolean, value: any) => { | ||
| if (isError) { | ||
| resolve(value) | ||
| } else { | ||
| reject(value) | ||
| this.emit("error", value) | ||
| } | ||
| }) | ||
| }) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| getReceiver<T>(r: string): Receiver<T> { | ||
| return new Proxy<Receiver<T>>({} as any, { | ||
| get: (target: any, p: string, receiver: any) => { | ||
| return (data: any) => { | ||
| this.receive(r, p, data) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| send(route: string, key: string, data: any, callback: (isOK: boolean, value: any) => void) { | ||
| if (this.isOpen) { | ||
| if (!this.mask) { | ||
| let cbs: { [key: string]: number } | undefined = undefined | ||
| for (const key in data) { | ||
| if (data.hasOwnProperty(key)) { | ||
| const element = data[key]; | ||
| if (typeof element == "function") { | ||
| this.ci++ | ||
| delete this.callbackPool[this.ci - this.callBackMaxIndex] | ||
| this.callbackPool[this.ci] = element | ||
| if (cbs == null) { | ||
| cbs = {} | ||
| } | ||
| cbs[key] = this.ci | ||
| } | ||
| } | ||
| } | ||
| let index: number | undefined = undefined | ||
| if (callback != null) { | ||
| this.ci++ | ||
| delete this.callbackPool[this.ci - this.callBackMaxIndex] | ||
| index = this.ci | ||
| this.callbackPool[this.ci] = callback | ||
| } | ||
| this.ws.send(this.pack.stringify( | ||
| { route: route, key: key, data: data, cbs: cbs, index: index } | ||
| )) | ||
| } else { | ||
| // console.log("弱网环境,send信息被忽略" + route) | ||
| callback(false, "弱网环境,send信息被忽略") | ||
| } | ||
| } else { | ||
| // console.log("游戏服务器未连接,send信息被忽略" + route) | ||
| callback(false, "服务器未连接,send信息被忽略") | ||
| } | ||
| } | ||
| receive(route: string, key: string, callback: (value: any) => void) { | ||
| this.router.on(route + "." + key, callback) | ||
| } | ||
| protected reLink() { | ||
| if (this.relinkCount < this.relinkMaxCount) { | ||
| this.relinkTimeOut = setTimeout(() => { | ||
| this.relinkTimeOut == null | ||
| this.relinkCount++ | ||
| this.link() | ||
| }, this.relinkTime) | ||
| } else { | ||
| this.relinkCount = 0 | ||
| this.emit("popup") | ||
| } | ||
| } | ||
| message(value: string) { | ||
| let obj: ISCMessage | ||
| try { | ||
| obj = this.pack.parse(value) | ||
| } catch { | ||
| throw new Error("服务器数据无法序列化") | ||
| } | ||
| this.pong() | ||
| if (obj.code == null) { | ||
| if (obj.route != null) { | ||
| if (obj.key == null) { | ||
| throw new Error("服务器数据出错") | ||
| } else { | ||
| this.router.emit(obj.route + "." + obj.key, obj.data) | ||
| } | ||
| } | ||
| } else if (obj.code == ReportCode.CALLBACK) { | ||
| if (obj.ci != null) { | ||
| let method = this.callbackPool[obj.ci] | ||
| if (method) { | ||
| method.apply(this, obj.args); | ||
| delete this.callbackPool[obj.ci] | ||
| } | ||
| } | ||
| } else if (obj.code == ReportCode.KICK) { | ||
| this.close() | ||
| } else { | ||
| this.emit("error", obj.error) | ||
| } | ||
| } | ||
| protected pong() { | ||
| this.emit("heartbeat") | ||
| this.pingIndex = 0 | ||
| this.mask = false | ||
| } | ||
| /** | ||
| * 这个callback 在重连里不会触发 | ||
| * 如需要触发 请使用 on("linked") | ||
| * @param callback | ||
| */ | ||
| link(callback?: () => void) { | ||
| this.isRelink = true | ||
| if (this.url == "" || this.url == null) { | ||
| throw new Error("服务器地址为空") | ||
| } else { | ||
| if (this.isBusy) { | ||
| throw new Error("重复连接服务") | ||
| } else { | ||
| this.ws = new WebSocket(this.url) | ||
| this.isBusy = true | ||
| this.emit("linking") | ||
| this.ws.onerror = () => { | ||
| this.emit("error", "网络出错") | ||
| } | ||
| this.ws.onopen = () => { | ||
| this.mask = false | ||
| this.relinkCount = 0 | ||
| this.isOpen = true | ||
| this.emit("linked") | ||
| if (callback) { | ||
| callback() | ||
| } | ||
| } | ||
| this.ws.onclose = () => { | ||
| this.mask = true | ||
| this.isOpen = false | ||
| this.isBusy = false | ||
| this.emit("suspend") | ||
| for (const key in this.callbackPool) { | ||
| if (Object.prototype.hasOwnProperty.call(this.callbackPool, key)) { | ||
| const element = this.callbackPool[key]; | ||
| element(false, "网络断开") | ||
| delete this.callbackPool[key] | ||
| } | ||
| } | ||
| if (this.isRelink) { | ||
| this.reLink() | ||
| } else { | ||
| this.emit("stop") | ||
| } | ||
| } | ||
| this.ws.onmessage = (evt) => { | ||
| this.message(evt.data.toString()) | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| close() { | ||
| if (this.relinkTimeOut) { | ||
| clearTimeout(this.relinkTimeOut) | ||
| this.relinkTimeOut == null | ||
| } | ||
| this.isRelink = false | ||
| this.isOpen = false | ||
| this.ws.close() | ||
| } | ||
| } |
+4
-10
| { | ||
| "name": "zero-remote", | ||
| "version": "1.1.3", | ||
| "version": "1.2.0", | ||
| "description": "常连接网络", | ||
| "main": "dist/index.js", | ||
| "scripts": { | ||
| "demo1": "ts-node-dev demo1.ts", | ||
| "demo2": "ts-node-dev demo2.ts" | ||
| }, | ||
| "scripts": {}, | ||
| "keywords": [ | ||
@@ -17,9 +14,6 @@ "网络", | ||
| "ws": "^7.4.2", | ||
| "zero-mvc": "^1.0.0" | ||
| "zero-dispatcher": "^1.2.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/ws": "^7.4.0", | ||
| "@types/node": "^14.14.16", | ||
| "ts-node-dev": "^1.1.6", | ||
| "typescript": "^4.1.5" | ||
| "@types/ws": "^7.4.0" | ||
| }, | ||
@@ -26,0 +20,0 @@ "author": "蓝面包wc24@qq.com", |
| { | ||
| "version": "0.2.0", | ||
| "configurations": [ | ||
| { | ||
| "type": "pwa-node", | ||
| "request": "launch", | ||
| "name": "服务", | ||
| "runtimeExecutable": "yarn", | ||
| "args": [ | ||
| "demo1", | ||
| ] | ||
| }, | ||
| { | ||
| "type": "pwa-node", | ||
| "request": "launch", | ||
| "name": "客户", | ||
| "runtimeExecutable": "yarn", | ||
| "args": [ | ||
| "demo2", | ||
| ] | ||
| }, | ||
| ] | ||
| } |
-648
| // import ws from "ws"; | ||
| // import { address as getLocalIp } from "ip" | ||
| // import ZeroRemote, { GameVisitor, IChannel, ICSMessage, ISCMessage, ReturnReceiver, ZeroRemoteClient } from "zero-remote"; | ||
| // type CMType = new (...ary: any[]) => ZeroServerNode | ||
| // type MType = new (...ary: any[]) => ZeroServerNode | ||
| // export let routeMap: WeakMap<CMType, string> = new WeakMap() | ||
| // export let balancePool: { [key: string]: (player: any, totle: number) => number } = {} | ||
| // /** | ||
| // * 装饰器 | ||
| // * @param key | ||
| // * @returns | ||
| // */ | ||
| // export function route(key: string) { | ||
| // return (type: CMType) => { | ||
| // routeMap.set(type, key) | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 装饰器 用去落点均衡 | ||
| // * @param callback | ||
| // * @returns | ||
| // */ | ||
| // export function balance<T extends UserInfo>(callback: (player: T, totle: number) => number) { | ||
| // return (type: MType) => { | ||
| // let route = getRoute(type) | ||
| // if (route) { | ||
| // balancePool[route] = callback | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 获取装饰器路由名 | ||
| // * @param connectorType | ||
| // * @returns | ||
| // */ | ||
| // export function getRoute(connectorType: new (...args: any[]) => any): string { | ||
| // let route = routeMap.get(connectorType) | ||
| // if (route) { | ||
| // return route | ||
| // } else { | ||
| // throw new Error("这个类没有@route") | ||
| // } | ||
| // } | ||
| // /** | ||
| // * server类型 | ||
| // */ | ||
| // enum ServerType { | ||
| // MODULE, | ||
| // CONNECT, | ||
| // SPECIAL, | ||
| // } | ||
| // interface IZeroServerCS { | ||
| // init: (value: { url: string, name: string, models: string[], type: ServerType, pid: number }) => void | ||
| // getPid: () => number | ||
| // addLine: (sid: number) => void | ||
| // removeLine: (sid: number) => void | ||
| // } | ||
| // interface IZeroServerInfo { | ||
| // url: string, | ||
| // models: string[], | ||
| // type: ServerType, | ||
| // sid: number | ||
| // } | ||
| // interface IZeroServerSC { | ||
| // clustered: (value: number) => void | ||
| // add: (value: IZeroServerInfo) => void | ||
| // remove: (value: number) => void | ||
| // } | ||
| // type ModuleType = new (...arg: any[]) => Module & { route: string } | ||
| // /** | ||
| // * server基类 | ||
| // */ | ||
| // export class ZeroServer extends ZeroRemoteClient { | ||
| // serverType: ServerType = ServerType.MODULE | ||
| // url: string; | ||
| // static mainUrl: string | ||
| // static modelPool: { [key: string]: Module } = {} | ||
| // models: any = [] | ||
| // clusterSender = this.getSender<IZeroServerCS>("") | ||
| // clusterReceiver = this.getReceiver<IZeroServerSC>("") | ||
| // static pid: number | ||
| // serverPool: { [key: string]: IZeroServerInfo } = {} | ||
| // name: string | ||
| // serverId!: number; | ||
| // isClustered: boolean = false | ||
| // constructor(public port: number) { | ||
| // super() | ||
| // this.name = this.constructor.name | ||
| // if (ZeroServer.mainUrl == null) { | ||
| // throw "请配置主服务器地址ZeroServer.mainUrl=\"XXX\"" | ||
| // } | ||
| // this.url = ZeroServer.mainUrl | ||
| // /** | ||
| // * 保存所有服务节点以方便扩展 | ||
| // */ | ||
| // this.clusterReceiver.add((info) => { | ||
| // this.serverPool[info.sid] = info | ||
| // }) | ||
| // this.clusterReceiver.clustered((sid: number) => { | ||
| // this.isClustered = true | ||
| // this.serverId = sid | ||
| // this.clustered() | ||
| // }) | ||
| // this.link() | ||
| // } | ||
| // clustered(): void { | ||
| // } | ||
| // showMask(): void { | ||
| // } | ||
| // hideMask(): void { | ||
| // } | ||
| // stringify(value: ISCMessage | ICSMessage): string { | ||
| // return JSON.stringify(value) | ||
| // } | ||
| // error(error: any): void { | ||
| // } | ||
| // linked(): void { | ||
| // if (ZeroServer.pid == null) { | ||
| // this.clusterSender.getPid().then((pid) => { | ||
| // if (ZeroServer.pid == null) { | ||
| // ZeroServer.pid = pid | ||
| // } | ||
| // this.sendInit() | ||
| // }) | ||
| // } else { | ||
| // this.sendInit() | ||
| // } | ||
| // } | ||
| // private sendInit() { | ||
| // this.clusterSender.init({ url: getLocalIp() + ":" + this.port, name: this.name, type: this.serverType, models: this.models, pid: ZeroServer.pid }) | ||
| // } | ||
| // /** | ||
| // * 生命不息 重连不止 | ||
| // */ | ||
| // popup(): void { | ||
| // console.log("集群失败") | ||
| // } | ||
| // linking(): void { | ||
| // } | ||
| // addModule(modelType: ModuleType) { | ||
| // let route = getRoute(modelType) | ||
| // if (route) { | ||
| // let model = new modelType(route) | ||
| // model.server = this | ||
| // model.start() | ||
| // ZeroServer.modelPool[route] = model | ||
| // this.models.push(route) | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 放在Connector服务上 | ||
| // * 用来连接Module的线路 | ||
| // */ | ||
| // class ClientFotModule extends ZeroRemoteClient { | ||
| // relinkMaxCount = 100 | ||
| // popupReLinkTime: number = 1000 | ||
| // popupReLinkTimeIndex!: NodeJS.Timeout; | ||
| // constructor(public url: string) { | ||
| // super() | ||
| // } | ||
| // showMask(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // hideMask(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // stringify(value: ICSMessage | ISCMessage): string { | ||
| // return JSON.stringify(value) | ||
| // } | ||
| // error(error: any): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // linked(): void { | ||
| // this.popupReLinkTime = 1000 | ||
| // } | ||
| // popup(): void { | ||
| // console.log("pppppp") | ||
| // for (const key in this.callbackPool) { | ||
| // const element = this.callbackPool[key]; | ||
| // console.log(element) | ||
| // element(false, "服务器被断开") | ||
| // } | ||
| // this.popupReLinkTimeIndex = setTimeout(() => { | ||
| // this.link() | ||
| // this.popupReLinkTime += 1000 | ||
| // }, this.popupReLinkTime) | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // linking(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 用户 | ||
| // */ | ||
| // export class ZeroServerUser<T extends UserInfo = UserInfo> extends GameVisitor { | ||
| // static pool: { [key: string]: ZeroServerUser } = {} | ||
| // static index: number = 0 | ||
| // static getAtuoId() { | ||
| // return this.index++ | ||
| // } | ||
| // clear(): void { | ||
| // } | ||
| // constructor(channel: IChannel<ISCMessage>, server: ZeroRemote, public info: T) { | ||
| // super(channel, server) | ||
| // ZeroServerUser.pool[info.userId] = this | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 连接服务器 用于连接用户 | ||
| // */ | ||
| // export class ConnectorServer<T extends UserInfo> extends ZeroServer { | ||
| // connectorTypePool: { [key: string]: new (...args: any[]) => Connector } = {}; | ||
| // serverType = ServerType.CONNECT | ||
| // modelsChannels: { [key: string]: ClientFotModule[] } = {}; | ||
| // constructor(port: number, private playerInfoType: new (sid: number, uid: number) => T) { | ||
| // super(port) | ||
| // } | ||
| // clustered() { | ||
| // console.log("创建连接服务:", this.serverId) | ||
| // new ZeroRemote(new ws.Server({ port: this.port }), (channel, server) => { | ||
| // let user = new ZeroServerUser(channel, server, new this.playerInfoType(this.serverId, ZeroServerUser.getAtuoId())) | ||
| // for (const key in this.connectorTypePool) { | ||
| // if (Object.prototype.hasOwnProperty.call(this.connectorTypePool, key)) { | ||
| // const element = this.connectorTypePool[key]; | ||
| // let connector = new element(this, user, key); | ||
| // connector.start() | ||
| // } | ||
| // } | ||
| // return user | ||
| // }) | ||
| // this.clusterReceiver.add((info) => { | ||
| // if (info.type == ServerType.MODULE) { | ||
| // let clientFotModule = new ClientFotModule("ws://" + info.url) | ||
| // clientFotModule.link(() => { | ||
| // this.clusterSender.addLine(info.sid) | ||
| // }) | ||
| // clientFotModule.receive("", "", this.partMessage.bind(this)) | ||
| // info.models.forEach((modelsName: string) => { | ||
| // let clinets = this.modelsChannels[modelsName] | ||
| // if (clinets == null) { | ||
| // clinets = [] | ||
| // this.modelsChannels[modelsName] = clinets | ||
| // } | ||
| // clinets.push(clientFotModule) | ||
| // }) | ||
| // } | ||
| // }) | ||
| // this.clusterReceiver.remove((info) => { | ||
| // }) | ||
| // } | ||
| // /** | ||
| // * 转发到前端 | ||
| // * @param data | ||
| // */ | ||
| // private partMessage(data: { key: string, data: any, userId: number, route: string }) { | ||
| // let user = ZeroServerUser.pool[data.userId] | ||
| // user.channel.send({ | ||
| // route: data.route, | ||
| // key: data.key, | ||
| // data: data.data | ||
| // }) | ||
| // } | ||
| // addConnector(connectorType: (new (...args: any[]) => Connector)) { | ||
| // let route = getRoute(connectorType) | ||
| // if (route) { | ||
| // this.connectorTypePool[route] = connectorType | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 有个CONNECT服务器做为客户端连了上来 | ||
| // * 添加 ping | ||
| // * 添加 callback | ||
| // * 添加 kick | ||
| // */ | ||
| // export class ConnectorVisitor extends GameVisitor { | ||
| // clear(): void { | ||
| // console.log("clear") | ||
| // } | ||
| // constructor(channel: IChannel<ISCMessage>, public moduleServer: ModuleServer) { | ||
| // super(channel, moduleServer.connectorServer) | ||
| // } | ||
| // handle(route: string, key: string, data: any, back: (Function | undefined)) { | ||
| // let model: any = ZeroServer.modelPool[route] | ||
| // let method: Function = model[key] | ||
| // if (method) { | ||
| // model.playerInfo = data.p | ||
| // model.isRemote = true | ||
| // let visitor = this.moduleServer.connectorVisitorPool[model.playerInfo.serverId] | ||
| // if (visitor == null) { | ||
| // this.moduleServer.connectorVisitorPool[model.playerInfo.serverId] = this | ||
| // } else { | ||
| // // console.log("这里应该为true", visitor == this) | ||
| // } | ||
| // let p = method.apply(model, data.a) | ||
| // if (back != null) { | ||
| // if (p instanceof Promise) { | ||
| // p.then((valueThen) => { | ||
| // back!(true, valueThen) | ||
| // }).catch((error) => { | ||
| // back!(false, error) | ||
| // }) | ||
| // } else { | ||
| // back(true, p) | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // export class ModuleServer extends ZeroServer { | ||
| // serverType = ServerType.MODULE | ||
| // connectorVisitorPool: { [key: string]: ConnectorVisitor } = {} | ||
| // connectorServer: ZeroRemote | ||
| // constructor(port: number) { | ||
| // super(port) | ||
| // this.connectorServer = new ZeroRemote(new ws.Server({ port: this.port }), (channel, server) => { | ||
| // return new ConnectorVisitor(channel, this) | ||
| // }) | ||
| // } | ||
| // clustered() { | ||
| // console.log("创建功能服务:", this.serverId) | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 被序列化的传递的用户信息 | ||
| // */ | ||
| // export class UserInfo { | ||
| // name: string | ||
| // /** | ||
| // * | ||
| // * @param serverId | ||
| // * @param userId 用于路由到用户不发给前端 | ||
| // */ | ||
| // constructor(public serverId: number, public userId: number) { | ||
| // this.name = "S" + serverId + "U" + userId | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 一个服务节点 | ||
| // */ | ||
| // export class ZeroServerNode { | ||
| // constructor(public route: string) { | ||
| // } | ||
| // start() { | ||
| // } | ||
| // } | ||
| // type Parameters<T> = T extends (...args: infer P) => any ? P : never; | ||
| // type ReturnType<T> = T extends (...args: any) => infer R ? R : any; | ||
| // export type ModuleSender<T> = { [K in keyof T]: ((value: Parameters<T[K]>[0], playerInfo?: UserInfo) => Promise<ReturnType<T[K]>>) } | ||
| // /** | ||
| // * | ||
| // */ | ||
| // export class Module<SC = any> extends ZeroServerNode { | ||
| // sender: ModuleSender<SC> | ||
| // public playerInfo!: UserInfo | ||
| // public isRemote: boolean = false | ||
| // public server!: ZeroServer | ||
| // constructor(route: string) { | ||
| // super(route) | ||
| // this.sender = new Proxy<ModuleSender<SC>>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // return (data: any, playerInfo: UserInfo | null = null) => { | ||
| // // let playerInfo | ||
| // if (playerInfo == null) { | ||
| // playerInfo = this.playerInfo | ||
| // } | ||
| // if (playerInfo) { | ||
| // if (this.isRemote) { | ||
| // let sendInfo = { | ||
| // route: "", | ||
| // key: "", | ||
| // data: { | ||
| // route: this.route, | ||
| // key: p, | ||
| // data: data, | ||
| // userId: playerInfo.userId | ||
| // } | ||
| // } | ||
| // let visitor = (this.server as ModuleServer).connectorVisitorPool[this.playerInfo.serverId] | ||
| // visitor.channel.send(sendInfo) | ||
| // } else { | ||
| // let sendInfo = { | ||
| // route: route, | ||
| // key: p, | ||
| // data: data | ||
| // } | ||
| // let user = ZeroServerUser.pool[playerInfo.userId] | ||
| // if (user != null) { | ||
| // user.channel.send(sendInfo) | ||
| // } else { | ||
| // console.warn("no User") | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
| // export class Connector<CS = any> extends ZeroServerNode { | ||
| // player!: ZeroServerUser<any> | ||
| // receiver: ReturnReceiver<CS>; | ||
| // private isFree: Boolean = true | ||
| // private lastCallback: (() => Promise<void>)[] = [] | ||
| // constructor(public server: ConnectorServer<any>, player: ZeroServerUser<any>, route: string) { | ||
| // super(route) | ||
| // this.player = player; | ||
| // this.route = route; | ||
| // /** | ||
| // * 接收来自己玩家的请求所有做了队例处理 防攻击 | ||
| // */ | ||
| // this.receiver = new Proxy<ReturnReceiver<CS>>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // return (callback: (value: any) => Promise<void>) => { | ||
| // let router = (this.player as any).routerPool[route] | ||
| // if (router == null) { | ||
| // router = {}; | ||
| // (this.player as any).routerPool[route] = router | ||
| // } | ||
| // router[p] = (...args: any) => { | ||
| // if (this.lastCallback.length >= 100) { | ||
| // this.player.kick() | ||
| // } else { | ||
| // this.lastCallback.push(() => { | ||
| // return callback.apply(null, args) | ||
| // }) | ||
| // } | ||
| // if (this.isFree) { | ||
| // this.isFree = false | ||
| // this.nextReceiver() | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // }) | ||
| // } | ||
| // private nextReceiver() { | ||
| // if (this.lastCallback.length > 0) { | ||
| // let callback = this.lastCallback.shift() | ||
| // if (callback) { | ||
| // callback().then(() => { | ||
| // this.nextReceiver() | ||
| // }).catch((err: Error | string) => { | ||
| // if (typeof err == "string") { | ||
| // this.player.error(err) | ||
| // } else { | ||
| // this.player.error(err.message) | ||
| // } | ||
| // this.nextReceiver() | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // this.isFree = true | ||
| // } | ||
| // } | ||
| // protected getModule<T extends Module>(modelType: new (...args: any[]) => T): T { | ||
| // let routeKey = getRoute(modelType) | ||
| // let model = ZeroServer.modelPool[routeKey] | ||
| // if (model == null) { | ||
| // let remoteModule = this.getRemoteModule(routeKey) | ||
| // return new Proxy<T>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // if (typeof modelType.prototype[p] == "function") { | ||
| // return (...args: any[]) => { | ||
| // console.log("__1__") | ||
| // return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { | ||
| // console.log("__2__") | ||
| // if (remoteModule == null) { | ||
| // remoteModule = this.getRemoteModule(routeKey) | ||
| // } | ||
| // if (remoteModule != null) { | ||
| // console.log("___3_") | ||
| // if (remoteModule.isOpen) { | ||
| // console.log("send") | ||
| // remoteModule.send(routeKey, p, { | ||
| // p: this.player.info, | ||
| // a: args | ||
| // }, (isError: boolean, value: any) => { | ||
| // if (isError) { | ||
| // resolve(value) | ||
| // } else { | ||
| // reject(value) | ||
| // } | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // reject("没有这个服务") | ||
| // } | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // //TODO | ||
| // } | ||
| // }, | ||
| // set: (target: T, p: string, value: any, receiver: any) => { | ||
| // console.log(p) | ||
| // return true | ||
| // } | ||
| // }) | ||
| // } else { | ||
| // return new Proxy<T>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // if (typeof modelType.prototype[p] == "function") { | ||
| // return (...args: any[]) => { | ||
| // model.playerInfo = this.player.info | ||
| // let _model: any = model | ||
| // return _model[p].apply(model, args) | ||
| // } | ||
| // } else { | ||
| // } | ||
| // }, | ||
| // set: (target: T, p: string, value: any, receiver: any) => { | ||
| // console.log(p) | ||
| // return true | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
| // getRemoteModule(routeKey: string): ClientFotModule | null { | ||
| // let remoteModules = this.server.modelsChannels[routeKey] | ||
| // if (remoteModules) { | ||
| // let pick = balancePool[routeKey](this.player, remoteModules.length) | ||
| // return remoteModules[pick] | ||
| // } else { | ||
| // return null | ||
| // } | ||
| // } | ||
| // } | ||
| // export default class ZeroCluster extends ZeroRemote<{ change: [] }> { | ||
| // constructor(port: number) { | ||
| // super(new ws.Server({ port: port }), (channel, server) => { | ||
| // return new ClusterVisitor(channel, server) | ||
| // }) | ||
| // } | ||
| // } | ||
| // export class ClusterVisitor extends GameVisitor { | ||
| // static serverIndex: number = 0 | ||
| // static serverPid: number = 0 | ||
| // static pool: { [url: string]: ClusterVisitor } = {} | ||
| // receiver = this.getReceiver<IZeroServerCS>("") | ||
| // sender = this.getSender<IZeroServerSC>("") | ||
| // url!: string | ||
| // name!: string | ||
| // models!: string[] | ||
| // sid!: number//在同一个server有相同的sid | ||
| // pid!: number//在同一内存中有相同的pid | ||
| // type!: ServerType; | ||
| // lines: Set<number> = new Set() | ||
| // clusterServer!: ZeroCluster | ||
| // start() { | ||
| // this.clusterServer = this.server | ||
| // this.receiver.init(async (info) => { | ||
| // //TODO 这里要加密 | ||
| // let server = ClusterVisitor.pool[info.url] | ||
| // if (server == null) { | ||
| // this.sid = ClusterVisitor.serverIndex | ||
| // this.url = info.url | ||
| // this.models = info.models | ||
| // this.type = info.type | ||
| // this.pid = info.pid | ||
| // this.name = info.name | ||
| // ClusterVisitor.serverIndex++ | ||
| // /** | ||
| // * 给自己发一个完成的信息 | ||
| // */ | ||
| // this.sender.clustered(this.sid) | ||
| // for (const key in ClusterVisitor.pool) { | ||
| // if (Object.prototype.hasOwnProperty.call(ClusterVisitor.pool, key)) { | ||
| // const element = ClusterVisitor.pool[key]; | ||
| // /** | ||
| // * 向新入加者发送已加入者信息 | ||
| // */ | ||
| // this.sender.add({ | ||
| // url: element.url, | ||
| // models: element.models, | ||
| // type: element.type, | ||
| // sid: element.sid, | ||
| // }) | ||
| // /** | ||
| // * 向所有已加入者发送新入加者信息 | ||
| // */ | ||
| // element.sender.add({ | ||
| // url: info.url, | ||
| // models: info.models, | ||
| // type: info.type, | ||
| // sid: this.sid, | ||
| // }) | ||
| // } | ||
| // } | ||
| // ClusterVisitor.pool[info.url] = this | ||
| // } else { | ||
| // console.log("出现URL重复") | ||
| // this.kick() | ||
| // } | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // this.receiver.getPid(async () => { | ||
| // return ClusterVisitor.serverPid++ | ||
| // }) | ||
| // this.receiver.addLine(async (sid) => { | ||
| // this.lines.add(sid) | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // this.receiver.removeLine(async (sid) => { | ||
| // this.lines.delete(sid) | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // } | ||
| // clear(): void { | ||
| // delete ClusterVisitor.pool[this.url] | ||
| // for (const key in ClusterVisitor.pool) { | ||
| // if (Object.prototype.hasOwnProperty.call(ClusterVisitor.pool, key)) { | ||
| // const element = ClusterVisitor.pool[key]; | ||
| // element.sender.remove(this.sid) | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
-103
| import ZeroRemote, { GameVisitor, ICSMessage, ISCMessage, ZeroRemoteClient } from "./index" | ||
| import ws from "ws" | ||
| import { T2 } from "./T2" | ||
| class User extends GameVisitor { | ||
| clear(): void { | ||
| } | ||
| a = 0 | ||
| start() { | ||
| this.getReceiver<T2>("fuck").getPid(async () => { | ||
| throw "fuck" | ||
| this.a++ | ||
| return this.a | ||
| }) | ||
| // this.getReceiver<T1>("fuck").on("fuck", (data) => { | ||
| // setTimeout(() => { | ||
| // data.b() | ||
| // }, 2000); | ||
| // }) | ||
| // this.getReceiver<T1>("fuck").fuck((data) => { | ||
| // console.log("___________") | ||
| // setTimeout(() => { | ||
| // data.b() | ||
| // }, 2000); | ||
| // return 5 | ||
| // }) | ||
| // this.getSender<T1>("tt").fuck({ | ||
| // a: 1, b: () => { | ||
| // console.log("____nonono") | ||
| // } | ||
| // }) | ||
| } | ||
| } | ||
| let zn = new ZeroRemote(new ws.Server({ port: 8888 }), (carer, server) => { | ||
| return new User(carer, server) | ||
| }) | ||
| //------------------------------------------------- | ||
| // interface A { | ||
| // init(a: string, b: number): number | ||
| // init2(): void | ||
| // } | ||
| // interface B { | ||
| // a(): void | ||
| // } | ||
| // /** | ||
| // * 新建服务 | ||
| // */ | ||
| // new ZeroRemote(new ws.Server({ port: 2000 }), (carer) => { | ||
| // return new RPCVisitor(carer) | ||
| // }) | ||
| // RPCVisitor.addRemote<A>(async (visitor) => { | ||
| // let a = await visitor.rs.init("a", 4) | ||
| // console.log("打印远程回调结果") | ||
| // console.log(a) | ||
| // }, "tt") | ||
| // RPCVisitor.addRemote<B>(async (visitor) => { | ||
| // let xx = async () => { | ||
| // await visitor.rs.a() | ||
| // xx() | ||
| // } | ||
| // xx() | ||
| // }) | ||
| // class CS extends RPCClient implements A { | ||
| // constructor() { | ||
| // super("ws:127.0.0.1:2000", "tt") | ||
| // } | ||
| // init(a: string, b: number): number { | ||
| // console.log(a) | ||
| // return 5 + b | ||
| // } | ||
| // init2(): void { | ||
| // console.log("_init2____") | ||
| // } | ||
| // } | ||
| // class CS2 extends RPCClient implements B { | ||
| // constructor() { | ||
| // super("ws:127.0.0.1:2000") | ||
| // } | ||
| // a(): void { | ||
| // console.log("aaa") | ||
| // } | ||
| // } | ||
| // let client = new CS() | ||
| // let client2 = new CS2() | ||
| // client.link() | ||
| // client.on("open", () => { | ||
| // console.log("rpc linked") | ||
| // }) | ||
| // client2.link() |
-32
| import { ICSMessage, ISCMessage, ZeroRemoteClient } from "." | ||
| import { T2 } from "./T2" | ||
| setTimeout(() => { | ||
| let cc = new ZeroRemoteClient("ws://192.168.16.195:8888") | ||
| cc.link(() => { | ||
| console.log("linkEd") | ||
| }) | ||
| cc.on("linked", () => { | ||
| console.log("linked") | ||
| }) | ||
| let sender = cc.getSender<T2>("fuck") | ||
| cc.on("showMask",()=>{ | ||
| console.log("showMask") | ||
| }) | ||
| setInterval(() => { | ||
| sender.getPid().then((a) => { | ||
| console.log(a) | ||
| }).catch((e) => { | ||
| console.log("___", e) | ||
| }) | ||
| // sender.tt("sss").then((a)=>{ | ||
| // console.log(a) | ||
| // }).catch((b)=>{ | ||
| // console.log(b) | ||
| // }) | ||
| }, 500) | ||
| }, 2000) | ||
-621
| "use strict"; | ||
| // import ws from "ws"; | ||
| // import { address as getLocalIp } from "ip" | ||
| // import ZeroRemote, { GameVisitor, IChannel, ICSMessage, ISCMessage, ReturnReceiver, ZeroRemoteClient } from "zero-remote"; | ||
| // type CMType = new (...ary: any[]) => ZeroServerNode | ||
| // type MType = new (...ary: any[]) => ZeroServerNode | ||
| // export let routeMap: WeakMap<CMType, string> = new WeakMap() | ||
| // export let balancePool: { [key: string]: (player: any, totle: number) => number } = {} | ||
| // /** | ||
| // * 装饰器 | ||
| // * @param key | ||
| // * @returns | ||
| // */ | ||
| // export function route(key: string) { | ||
| // return (type: CMType) => { | ||
| // routeMap.set(type, key) | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 装饰器 用去落点均衡 | ||
| // * @param callback | ||
| // * @returns | ||
| // */ | ||
| // export function balance<T extends UserInfo>(callback: (player: T, totle: number) => number) { | ||
| // return (type: MType) => { | ||
| // let route = getRoute(type) | ||
| // if (route) { | ||
| // balancePool[route] = callback | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 获取装饰器路由名 | ||
| // * @param connectorType | ||
| // * @returns | ||
| // */ | ||
| // export function getRoute(connectorType: new (...args: any[]) => any): string { | ||
| // let route = routeMap.get(connectorType) | ||
| // if (route) { | ||
| // return route | ||
| // } else { | ||
| // throw new Error("这个类没有@route") | ||
| // } | ||
| // } | ||
| // /** | ||
| // * server类型 | ||
| // */ | ||
| // enum ServerType { | ||
| // MODULE, | ||
| // CONNECT, | ||
| // SPECIAL, | ||
| // } | ||
| // interface IZeroServerCS { | ||
| // init: (value: { url: string, name: string, models: string[], type: ServerType, pid: number }) => void | ||
| // getPid: () => number | ||
| // addLine: (sid: number) => void | ||
| // removeLine: (sid: number) => void | ||
| // } | ||
| // interface IZeroServerInfo { | ||
| // url: string, | ||
| // models: string[], | ||
| // type: ServerType, | ||
| // sid: number | ||
| // } | ||
| // interface IZeroServerSC { | ||
| // clustered: (value: number) => void | ||
| // add: (value: IZeroServerInfo) => void | ||
| // remove: (value: number) => void | ||
| // } | ||
| // type ModuleType = new (...arg: any[]) => Module & { route: string } | ||
| // /** | ||
| // * server基类 | ||
| // */ | ||
| // export class ZeroServer extends ZeroRemoteClient { | ||
| // serverType: ServerType = ServerType.MODULE | ||
| // url: string; | ||
| // static mainUrl: string | ||
| // static modelPool: { [key: string]: Module } = {} | ||
| // models: any = [] | ||
| // clusterSender = this.getSender<IZeroServerCS>("") | ||
| // clusterReceiver = this.getReceiver<IZeroServerSC>("") | ||
| // static pid: number | ||
| // serverPool: { [key: string]: IZeroServerInfo } = {} | ||
| // name: string | ||
| // serverId!: number; | ||
| // isClustered: boolean = false | ||
| // constructor(public port: number) { | ||
| // super() | ||
| // this.name = this.constructor.name | ||
| // if (ZeroServer.mainUrl == null) { | ||
| // throw "请配置主服务器地址ZeroServer.mainUrl=\"XXX\"" | ||
| // } | ||
| // this.url = ZeroServer.mainUrl | ||
| // /** | ||
| // * 保存所有服务节点以方便扩展 | ||
| // */ | ||
| // this.clusterReceiver.add((info) => { | ||
| // this.serverPool[info.sid] = info | ||
| // }) | ||
| // this.clusterReceiver.clustered((sid: number) => { | ||
| // this.isClustered = true | ||
| // this.serverId = sid | ||
| // this.clustered() | ||
| // }) | ||
| // this.link() | ||
| // } | ||
| // clustered(): void { | ||
| // } | ||
| // showMask(): void { | ||
| // } | ||
| // hideMask(): void { | ||
| // } | ||
| // stringify(value: ISCMessage | ICSMessage): string { | ||
| // return JSON.stringify(value) | ||
| // } | ||
| // error(error: any): void { | ||
| // } | ||
| // linked(): void { | ||
| // if (ZeroServer.pid == null) { | ||
| // this.clusterSender.getPid().then((pid) => { | ||
| // if (ZeroServer.pid == null) { | ||
| // ZeroServer.pid = pid | ||
| // } | ||
| // this.sendInit() | ||
| // }) | ||
| // } else { | ||
| // this.sendInit() | ||
| // } | ||
| // } | ||
| // private sendInit() { | ||
| // this.clusterSender.init({ url: getLocalIp() + ":" + this.port, name: this.name, type: this.serverType, models: this.models, pid: ZeroServer.pid }) | ||
| // } | ||
| // /** | ||
| // * 生命不息 重连不止 | ||
| // */ | ||
| // popup(): void { | ||
| // console.log("集群失败") | ||
| // } | ||
| // linking(): void { | ||
| // } | ||
| // addModule(modelType: ModuleType) { | ||
| // let route = getRoute(modelType) | ||
| // if (route) { | ||
| // let model = new modelType(route) | ||
| // model.server = this | ||
| // model.start() | ||
| // ZeroServer.modelPool[route] = model | ||
| // this.models.push(route) | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 放在Connector服务上 | ||
| // * 用来连接Module的线路 | ||
| // */ | ||
| // class ClientFotModule extends ZeroRemoteClient { | ||
| // relinkMaxCount = 100 | ||
| // popupReLinkTime: number = 1000 | ||
| // popupReLinkTimeIndex!: NodeJS.Timeout; | ||
| // constructor(public url: string) { | ||
| // super() | ||
| // } | ||
| // showMask(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // hideMask(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // stringify(value: ICSMessage | ISCMessage): string { | ||
| // return JSON.stringify(value) | ||
| // } | ||
| // error(error: any): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // linked(): void { | ||
| // this.popupReLinkTime = 1000 | ||
| // } | ||
| // popup(): void { | ||
| // console.log("pppppp") | ||
| // for (const key in this.callbackPool) { | ||
| // const element = this.callbackPool[key]; | ||
| // console.log(element) | ||
| // element(false, "服务器被断开") | ||
| // } | ||
| // this.popupReLinkTimeIndex = setTimeout(() => { | ||
| // this.link() | ||
| // this.popupReLinkTime += 1000 | ||
| // }, this.popupReLinkTime) | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // linking(): void { | ||
| // // throw new Error("Method not implemented."); | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 用户 | ||
| // */ | ||
| // export class ZeroServerUser<T extends UserInfo = UserInfo> extends GameVisitor { | ||
| // static pool: { [key: string]: ZeroServerUser } = {} | ||
| // static index: number = 0 | ||
| // static getAtuoId() { | ||
| // return this.index++ | ||
| // } | ||
| // clear(): void { | ||
| // } | ||
| // constructor(channel: IChannel<ISCMessage>, server: ZeroRemote, public info: T) { | ||
| // super(channel, server) | ||
| // ZeroServerUser.pool[info.userId] = this | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 连接服务器 用于连接用户 | ||
| // */ | ||
| // export class ConnectorServer<T extends UserInfo> extends ZeroServer { | ||
| // connectorTypePool: { [key: string]: new (...args: any[]) => Connector } = {}; | ||
| // serverType = ServerType.CONNECT | ||
| // modelsChannels: { [key: string]: ClientFotModule[] } = {}; | ||
| // constructor(port: number, private playerInfoType: new (sid: number, uid: number) => T) { | ||
| // super(port) | ||
| // } | ||
| // clustered() { | ||
| // console.log("创建连接服务:", this.serverId) | ||
| // new ZeroRemote(new ws.Server({ port: this.port }), (channel, server) => { | ||
| // let user = new ZeroServerUser(channel, server, new this.playerInfoType(this.serverId, ZeroServerUser.getAtuoId())) | ||
| // for (const key in this.connectorTypePool) { | ||
| // if (Object.prototype.hasOwnProperty.call(this.connectorTypePool, key)) { | ||
| // const element = this.connectorTypePool[key]; | ||
| // let connector = new element(this, user, key); | ||
| // connector.start() | ||
| // } | ||
| // } | ||
| // return user | ||
| // }) | ||
| // this.clusterReceiver.add((info) => { | ||
| // if (info.type == ServerType.MODULE) { | ||
| // let clientFotModule = new ClientFotModule("ws://" + info.url) | ||
| // clientFotModule.link(() => { | ||
| // this.clusterSender.addLine(info.sid) | ||
| // }) | ||
| // clientFotModule.receive("", "", this.partMessage.bind(this)) | ||
| // info.models.forEach((modelsName: string) => { | ||
| // let clinets = this.modelsChannels[modelsName] | ||
| // if (clinets == null) { | ||
| // clinets = [] | ||
| // this.modelsChannels[modelsName] = clinets | ||
| // } | ||
| // clinets.push(clientFotModule) | ||
| // }) | ||
| // } | ||
| // }) | ||
| // this.clusterReceiver.remove((info) => { | ||
| // }) | ||
| // } | ||
| // /** | ||
| // * 转发到前端 | ||
| // * @param data | ||
| // */ | ||
| // private partMessage(data: { key: string, data: any, userId: number, route: string }) { | ||
| // let user = ZeroServerUser.pool[data.userId] | ||
| // user.channel.send({ | ||
| // route: data.route, | ||
| // key: data.key, | ||
| // data: data.data | ||
| // }) | ||
| // } | ||
| // addConnector(connectorType: (new (...args: any[]) => Connector)) { | ||
| // let route = getRoute(connectorType) | ||
| // if (route) { | ||
| // this.connectorTypePool[route] = connectorType | ||
| // } | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 有个CONNECT服务器做为客户端连了上来 | ||
| // * 添加 ping | ||
| // * 添加 callback | ||
| // * 添加 kick | ||
| // */ | ||
| // export class ConnectorVisitor extends GameVisitor { | ||
| // clear(): void { | ||
| // console.log("clear") | ||
| // } | ||
| // constructor(channel: IChannel<ISCMessage>, public moduleServer: ModuleServer) { | ||
| // super(channel, moduleServer.connectorServer) | ||
| // } | ||
| // handle(route: string, key: string, data: any, back: (Function | undefined)) { | ||
| // let model: any = ZeroServer.modelPool[route] | ||
| // let method: Function = model[key] | ||
| // if (method) { | ||
| // model.playerInfo = data.p | ||
| // model.isRemote = true | ||
| // let visitor = this.moduleServer.connectorVisitorPool[model.playerInfo.serverId] | ||
| // if (visitor == null) { | ||
| // this.moduleServer.connectorVisitorPool[model.playerInfo.serverId] = this | ||
| // } else { | ||
| // // console.log("这里应该为true", visitor == this) | ||
| // } | ||
| // let p = method.apply(model, data.a) | ||
| // if (back != null) { | ||
| // if (p instanceof Promise) { | ||
| // p.then((valueThen) => { | ||
| // back!(true, valueThen) | ||
| // }).catch((error) => { | ||
| // back!(false, error) | ||
| // }) | ||
| // } else { | ||
| // back(true, p) | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // export class ModuleServer extends ZeroServer { | ||
| // serverType = ServerType.MODULE | ||
| // connectorVisitorPool: { [key: string]: ConnectorVisitor } = {} | ||
| // connectorServer: ZeroRemote | ||
| // constructor(port: number) { | ||
| // super(port) | ||
| // this.connectorServer = new ZeroRemote(new ws.Server({ port: this.port }), (channel, server) => { | ||
| // return new ConnectorVisitor(channel, this) | ||
| // }) | ||
| // } | ||
| // clustered() { | ||
| // console.log("创建功能服务:", this.serverId) | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 被序列化的传递的用户信息 | ||
| // */ | ||
| // export class UserInfo { | ||
| // name: string | ||
| // /** | ||
| // * | ||
| // * @param serverId | ||
| // * @param userId 用于路由到用户不发给前端 | ||
| // */ | ||
| // constructor(public serverId: number, public userId: number) { | ||
| // this.name = "S" + serverId + "U" + userId | ||
| // } | ||
| // } | ||
| // /** | ||
| // * 一个服务节点 | ||
| // */ | ||
| // export class ZeroServerNode { | ||
| // constructor(public route: string) { | ||
| // } | ||
| // start() { | ||
| // } | ||
| // } | ||
| // type Parameters<T> = T extends (...args: infer P) => any ? P : never; | ||
| // type ReturnType<T> = T extends (...args: any) => infer R ? R : any; | ||
| // export type ModuleSender<T> = { [K in keyof T]: ((value: Parameters<T[K]>[0], playerInfo?: UserInfo) => Promise<ReturnType<T[K]>>) } | ||
| // /** | ||
| // * | ||
| // */ | ||
| // export class Module<SC = any> extends ZeroServerNode { | ||
| // sender: ModuleSender<SC> | ||
| // public playerInfo!: UserInfo | ||
| // public isRemote: boolean = false | ||
| // public server!: ZeroServer | ||
| // constructor(route: string) { | ||
| // super(route) | ||
| // this.sender = new Proxy<ModuleSender<SC>>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // return (data: any, playerInfo: UserInfo | null = null) => { | ||
| // // let playerInfo | ||
| // if (playerInfo == null) { | ||
| // playerInfo = this.playerInfo | ||
| // } | ||
| // if (playerInfo) { | ||
| // if (this.isRemote) { | ||
| // let sendInfo = { | ||
| // route: "", | ||
| // key: "", | ||
| // data: { | ||
| // route: this.route, | ||
| // key: p, | ||
| // data: data, | ||
| // userId: playerInfo.userId | ||
| // } | ||
| // } | ||
| // let visitor = (this.server as ModuleServer).connectorVisitorPool[this.playerInfo.serverId] | ||
| // visitor.channel.send(sendInfo) | ||
| // } else { | ||
| // let sendInfo = { | ||
| // route: route, | ||
| // key: p, | ||
| // data: data | ||
| // } | ||
| // let user = ZeroServerUser.pool[playerInfo.userId] | ||
| // if (user != null) { | ||
| // user.channel.send(sendInfo) | ||
| // } else { | ||
| // console.warn("no User") | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
| // export class Connector<CS = any> extends ZeroServerNode { | ||
| // player!: ZeroServerUser<any> | ||
| // receiver: ReturnReceiver<CS>; | ||
| // private isFree: Boolean = true | ||
| // private lastCallback: (() => Promise<void>)[] = [] | ||
| // constructor(public server: ConnectorServer<any>, player: ZeroServerUser<any>, route: string) { | ||
| // super(route) | ||
| // this.player = player; | ||
| // this.route = route; | ||
| // /** | ||
| // * 接收来自己玩家的请求所有做了队例处理 防攻击 | ||
| // */ | ||
| // this.receiver = new Proxy<ReturnReceiver<CS>>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // return (callback: (value: any) => Promise<void>) => { | ||
| // let router = (this.player as any).routerPool[route] | ||
| // if (router == null) { | ||
| // router = {}; | ||
| // (this.player as any).routerPool[route] = router | ||
| // } | ||
| // router[p] = (...args: any) => { | ||
| // if (this.lastCallback.length >= 100) { | ||
| // this.player.kick() | ||
| // } else { | ||
| // this.lastCallback.push(() => { | ||
| // return callback.apply(null, args) | ||
| // }) | ||
| // } | ||
| // if (this.isFree) { | ||
| // this.isFree = false | ||
| // this.nextReceiver() | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
| // }) | ||
| // } | ||
| // private nextReceiver() { | ||
| // if (this.lastCallback.length > 0) { | ||
| // let callback = this.lastCallback.shift() | ||
| // if (callback) { | ||
| // callback().then(() => { | ||
| // this.nextReceiver() | ||
| // }).catch((err: Error | string) => { | ||
| // if (typeof err == "string") { | ||
| // this.player.error(err) | ||
| // } else { | ||
| // this.player.error(err.message) | ||
| // } | ||
| // this.nextReceiver() | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // this.isFree = true | ||
| // } | ||
| // } | ||
| // protected getModule<T extends Module>(modelType: new (...args: any[]) => T): T { | ||
| // let routeKey = getRoute(modelType) | ||
| // let model = ZeroServer.modelPool[routeKey] | ||
| // if (model == null) { | ||
| // let remoteModule = this.getRemoteModule(routeKey) | ||
| // return new Proxy<T>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // if (typeof modelType.prototype[p] == "function") { | ||
| // return (...args: any[]) => { | ||
| // console.log("__1__") | ||
| // return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { | ||
| // console.log("__2__") | ||
| // if (remoteModule == null) { | ||
| // remoteModule = this.getRemoteModule(routeKey) | ||
| // } | ||
| // if (remoteModule != null) { | ||
| // console.log("___3_") | ||
| // if (remoteModule.isOpen) { | ||
| // console.log("send") | ||
| // remoteModule.send(routeKey, p, { | ||
| // p: this.player.info, | ||
| // a: args | ||
| // }, (isError: boolean, value: any) => { | ||
| // if (isError) { | ||
| // resolve(value) | ||
| // } else { | ||
| // reject(value) | ||
| // } | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // reject("没有这个服务") | ||
| // } | ||
| // }) | ||
| // } | ||
| // } else { | ||
| // //TODO | ||
| // } | ||
| // }, | ||
| // set: (target: T, p: string, value: any, receiver: any) => { | ||
| // console.log(p) | ||
| // return true | ||
| // } | ||
| // }) | ||
| // } else { | ||
| // return new Proxy<T>({} as any, { | ||
| // get: (target: any, p: string, receiver: any) => { | ||
| // if (typeof modelType.prototype[p] == "function") { | ||
| // return (...args: any[]) => { | ||
| // model.playerInfo = this.player.info | ||
| // let _model: any = model | ||
| // return _model[p].apply(model, args) | ||
| // } | ||
| // } else { | ||
| // } | ||
| // }, | ||
| // set: (target: T, p: string, value: any, receiver: any) => { | ||
| // console.log(p) | ||
| // return true | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
| // getRemoteModule(routeKey: string): ClientFotModule | null { | ||
| // let remoteModules = this.server.modelsChannels[routeKey] | ||
| // if (remoteModules) { | ||
| // let pick = balancePool[routeKey](this.player, remoteModules.length) | ||
| // return remoteModules[pick] | ||
| // } else { | ||
| // return null | ||
| // } | ||
| // } | ||
| // } | ||
| // export default class ZeroCluster extends ZeroRemote<{ change: [] }> { | ||
| // constructor(port: number) { | ||
| // super(new ws.Server({ port: port }), (channel, server) => { | ||
| // return new ClusterVisitor(channel, server) | ||
| // }) | ||
| // } | ||
| // } | ||
| // export class ClusterVisitor extends GameVisitor { | ||
| // static serverIndex: number = 0 | ||
| // static serverPid: number = 0 | ||
| // static pool: { [url: string]: ClusterVisitor } = {} | ||
| // receiver = this.getReceiver<IZeroServerCS>("") | ||
| // sender = this.getSender<IZeroServerSC>("") | ||
| // url!: string | ||
| // name!: string | ||
| // models!: string[] | ||
| // sid!: number//在同一个server有相同的sid | ||
| // pid!: number//在同一内存中有相同的pid | ||
| // type!: ServerType; | ||
| // lines: Set<number> = new Set() | ||
| // clusterServer!: ZeroCluster | ||
| // start() { | ||
| // this.clusterServer = this.server | ||
| // this.receiver.init(async (info) => { | ||
| // //TODO 这里要加密 | ||
| // let server = ClusterVisitor.pool[info.url] | ||
| // if (server == null) { | ||
| // this.sid = ClusterVisitor.serverIndex | ||
| // this.url = info.url | ||
| // this.models = info.models | ||
| // this.type = info.type | ||
| // this.pid = info.pid | ||
| // this.name = info.name | ||
| // ClusterVisitor.serverIndex++ | ||
| // /** | ||
| // * 给自己发一个完成的信息 | ||
| // */ | ||
| // this.sender.clustered(this.sid) | ||
| // for (const key in ClusterVisitor.pool) { | ||
| // if (Object.prototype.hasOwnProperty.call(ClusterVisitor.pool, key)) { | ||
| // const element = ClusterVisitor.pool[key]; | ||
| // /** | ||
| // * 向新入加者发送已加入者信息 | ||
| // */ | ||
| // this.sender.add({ | ||
| // url: element.url, | ||
| // models: element.models, | ||
| // type: element.type, | ||
| // sid: element.sid, | ||
| // }) | ||
| // /** | ||
| // * 向所有已加入者发送新入加者信息 | ||
| // */ | ||
| // element.sender.add({ | ||
| // url: info.url, | ||
| // models: info.models, | ||
| // type: info.type, | ||
| // sid: this.sid, | ||
| // }) | ||
| // } | ||
| // } | ||
| // ClusterVisitor.pool[info.url] = this | ||
| // } else { | ||
| // console.log("出现URL重复") | ||
| // this.kick() | ||
| // } | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // this.receiver.getPid(async () => { | ||
| // return ClusterVisitor.serverPid++ | ||
| // }) | ||
| // this.receiver.addLine(async (sid) => { | ||
| // this.lines.add(sid) | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // this.receiver.removeLine(async (sid) => { | ||
| // this.lines.delete(sid) | ||
| // this.clusterServer.emit("change") | ||
| // }) | ||
| // } | ||
| // clear(): void { | ||
| // delete ClusterVisitor.pool[this.url] | ||
| // for (const key in ClusterVisitor.pool) { | ||
| // if (Object.prototype.hasOwnProperty.call(ClusterVisitor.pool, key)) { | ||
| // const element = ClusterVisitor.pool[key]; | ||
| // element.sender.remove(this.sid) | ||
| // } | ||
| // } | ||
| // } | ||
| // } |
-123
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
| return new (P || (P = Promise))(function (resolve, reject) { | ||
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
| }); | ||
| }; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const index_1 = __importStar(require("./index")); | ||
| const ws_1 = __importDefault(require("ws")); | ||
| class User extends index_1.GameVisitor { | ||
| constructor() { | ||
| super(...arguments); | ||
| this.a = 0; | ||
| } | ||
| clear() { | ||
| } | ||
| start() { | ||
| this.getReceiver("fuck").getPid(() => __awaiter(this, void 0, void 0, function* () { | ||
| throw "fuck"; | ||
| this.a++; | ||
| return this.a; | ||
| })); | ||
| // this.getReceiver<T1>("fuck").on("fuck", (data) => { | ||
| // setTimeout(() => { | ||
| // data.b() | ||
| // }, 2000); | ||
| // }) | ||
| // this.getReceiver<T1>("fuck").fuck((data) => { | ||
| // console.log("___________") | ||
| // setTimeout(() => { | ||
| // data.b() | ||
| // }, 2000); | ||
| // return 5 | ||
| // }) | ||
| // this.getSender<T1>("tt").fuck({ | ||
| // a: 1, b: () => { | ||
| // console.log("____nonono") | ||
| // } | ||
| // }) | ||
| } | ||
| } | ||
| let zn = new index_1.default(new ws_1.default.Server({ port: 8888 }), (carer, server) => { | ||
| return new User(carer, server); | ||
| }); | ||
| //------------------------------------------------- | ||
| // interface A { | ||
| // init(a: string, b: number): number | ||
| // init2(): void | ||
| // } | ||
| // interface B { | ||
| // a(): void | ||
| // } | ||
| // /** | ||
| // * 新建服务 | ||
| // */ | ||
| // new ZeroRemote(new ws.Server({ port: 2000 }), (carer) => { | ||
| // return new RPCVisitor(carer) | ||
| // }) | ||
| // RPCVisitor.addRemote<A>(async (visitor) => { | ||
| // let a = await visitor.rs.init("a", 4) | ||
| // console.log("打印远程回调结果") | ||
| // console.log(a) | ||
| // }, "tt") | ||
| // RPCVisitor.addRemote<B>(async (visitor) => { | ||
| // let xx = async () => { | ||
| // await visitor.rs.a() | ||
| // xx() | ||
| // } | ||
| // xx() | ||
| // }) | ||
| // class CS extends RPCClient implements A { | ||
| // constructor() { | ||
| // super("ws:127.0.0.1:2000", "tt") | ||
| // } | ||
| // init(a: string, b: number): number { | ||
| // console.log(a) | ||
| // return 5 + b | ||
| // } | ||
| // init2(): void { | ||
| // console.log("_init2____") | ||
| // } | ||
| // } | ||
| // class CS2 extends RPCClient implements B { | ||
| // constructor() { | ||
| // super("ws:127.0.0.1:2000") | ||
| // } | ||
| // a(): void { | ||
| // console.log("aaa") | ||
| // } | ||
| // } | ||
| // let client = new CS() | ||
| // let client2 = new CS2() | ||
| // client.link() | ||
| // client.on("open", () => { | ||
| // console.log("rpc linked") | ||
| // }) | ||
| // client2.link() |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const _1 = require("."); | ||
| setTimeout(() => { | ||
| let cc = new _1.ZeroRemoteClient("ws://192.168.16.195:8888"); | ||
| cc.link(() => { | ||
| console.log("linkEd"); | ||
| }); | ||
| cc.on("linked", () => { | ||
| console.log("linked"); | ||
| }); | ||
| let sender = cc.getSender("fuck"); | ||
| cc.on("showMask", () => { | ||
| console.log("showMask"); | ||
| }); | ||
| setInterval(() => { | ||
| sender.getPid().then((a) => { | ||
| console.log(a); | ||
| }).catch((e) => { | ||
| console.log("___", e); | ||
| }); | ||
| // sender.tt("sss").then((a)=>{ | ||
| // console.log(a) | ||
| // }).catch((b)=>{ | ||
| // console.log(b) | ||
| // }) | ||
| }, 500); | ||
| }, 2000); |
-324
| "use strict"; | ||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
| return new (P || (P = Promise))(function (resolve, reject) { | ||
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
| }); | ||
| }; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.RPCClient = exports.RPCVisitor = exports.RPCCode = void 0; | ||
| const zero_mvc_1 = require("zero-mvc"); | ||
| const _1 = require("."); | ||
| const ws_1 = __importDefault(require("ws")); | ||
| var RPCCode; | ||
| (function (RPCCode) { | ||
| RPCCode[RPCCode["INITIATIVE"] = 0] = "INITIATIVE"; | ||
| RPCCode[RPCCode["FAIL"] = 1] = "FAIL"; | ||
| RPCCode[RPCCode["CALLBACK"] = 50] = "CALLBACK"; | ||
| RPCCode[RPCCode["SUCCESS"] = 200] = "SUCCESS"; | ||
| RPCCode[RPCCode["KICK"] = 30] = "KICK"; | ||
| })(RPCCode = exports.RPCCode || (exports.RPCCode = {})); | ||
| class RPCHandle { | ||
| constructor(carer, owner) { | ||
| this.carer = carer; | ||
| this.owner = owner; | ||
| this.target = null; | ||
| this.callbackStack = new _1.LiteStack(); | ||
| let k; | ||
| let f = (...args) => { | ||
| return new Promise((resolve, reject) => { | ||
| let cbs = {}; | ||
| args.forEach((arg, index) => { | ||
| if (typeof arg == "function") { | ||
| cbs[index] = this.callbackStack.push({ resolve: arg }); | ||
| } | ||
| }); | ||
| this.carer.send({ | ||
| code: RPCCode.INITIATIVE, | ||
| key: k, | ||
| args: args, | ||
| cbs: cbs, | ||
| index: this.callbackStack.push({ resolve: resolve, reject: reject }), | ||
| }); | ||
| if (this.callbackStack.size > RPCHandle.callbackMaxStack) { | ||
| this.callbackStack.clear(RPCHandle.callbackMaxStack / 2); | ||
| } | ||
| }); | ||
| }; | ||
| this.rs = new Proxy({}, { | ||
| get: (target, p, receiver) => { | ||
| k = p; | ||
| return f; | ||
| } | ||
| }); | ||
| } | ||
| receive(body) { | ||
| if (body.code == RPCCode.INITIATIVE || body.code == RPCCode.SUCCESS) { | ||
| let target; | ||
| if (this.target && this.target[body.key] != null) { | ||
| target = this.target; | ||
| } | ||
| else if (this.owner[body.key] == null) { | ||
| target = this.target; | ||
| } | ||
| else { | ||
| target = this.owner; | ||
| } | ||
| if (target == null) { | ||
| this.reject(body.index, "no remote traget " + body.key); | ||
| } | ||
| else { | ||
| let method = target[body.key]; | ||
| if (method) { | ||
| if (body.cbs) { | ||
| for (const key in body.cbs) { | ||
| if (body.cbs.hasOwnProperty(key)) { | ||
| const element = body.cbs[key]; | ||
| body.args[key] = (...CbArgs) => { | ||
| this.carer.send({ | ||
| code: RPCCode.CALLBACK, | ||
| key: element, | ||
| args: CbArgs | ||
| }); | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| Promise.resolve(method.apply(target, body.args || [])).then((value) => { | ||
| this.carer.send({ | ||
| code: RPCCode.CALLBACK, | ||
| key: body.index, | ||
| args: [value] | ||
| }); | ||
| }).catch(err => { | ||
| console.log(err); | ||
| }); | ||
| } | ||
| else { | ||
| this.reject(body.index, "no remote method " + body.key); | ||
| } | ||
| } | ||
| } | ||
| else if (body.code == RPCCode.CALLBACK) { | ||
| let method = this.callbackStack.pull(body.key); | ||
| if (method) { | ||
| method.resolve.apply(null, body.args); | ||
| } | ||
| else { | ||
| this.error(); | ||
| } | ||
| body.args; | ||
| } | ||
| else if (body.code == RPCCode.FAIL) { | ||
| if (body.key != null) { | ||
| let method = this.callbackStack.pull(body.key); | ||
| if (method && method.reject) { | ||
| method.reject(body.error); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| error(value) { | ||
| this.carer.send({ | ||
| code: RPCCode.FAIL, | ||
| error: value, | ||
| }); | ||
| } | ||
| reject(key, value) { | ||
| this.carer.send({ | ||
| code: RPCCode.FAIL, | ||
| key: key, | ||
| error: value, | ||
| }); | ||
| } | ||
| } | ||
| RPCHandle.callbackMaxStack = 20; | ||
| /** | ||
| * RPC模式下的用户 | ||
| * 回调函数在第没有被调用的情况下会被回收 | ||
| */ | ||
| class RPCVisitor extends _1.Visitor { | ||
| constructor(carer, server) { | ||
| super(carer, server); | ||
| this.key = null; | ||
| this.handle = new RPCHandle(carer, this); | ||
| this.handle.rs.getKey().then((key) => { | ||
| this.key = key; | ||
| let callback = RPCVisitor.remotePool[key]; | ||
| if (callback) { | ||
| callback(this).catch((err) => { | ||
| console.warn(err); | ||
| }); | ||
| } | ||
| else { | ||
| console.log("主没上没有命名为\"" + key + "\"的的RPC服务"); | ||
| } | ||
| }).catch((err) => { | ||
| console.log(err, "rpc error"); | ||
| }); | ||
| } | ||
| set owner(value) { | ||
| this.handle.target = value; | ||
| } | ||
| /** | ||
| * RemoteServer | ||
| * 远程服务 | ||
| */ | ||
| get rs() { | ||
| return this.handle.rs; | ||
| } | ||
| static addRemote(callback, key = "") { | ||
| RPCVisitor.remotePool[key] = callback; | ||
| } | ||
| ping() { | ||
| return true; | ||
| } | ||
| error(value) { | ||
| this.handle.error(value); | ||
| } | ||
| receive(body) { | ||
| this.handle.receive(body); | ||
| } | ||
| clear() { | ||
| } | ||
| } | ||
| exports.RPCVisitor = RPCVisitor; | ||
| RPCVisitor.remotePool = {}; | ||
| /** | ||
| * RPC模式 客户端 | ||
| * 支持 双向 添加回调函数 | ||
| * 支持返回值 | ||
| * 支持智能提示 | ||
| * 支持一对多 | ||
| */ | ||
| class RPCClient extends zero_mvc_1.ZeroDispatcher { | ||
| constructor(address, key = "", pack = _1.jsonPack) { | ||
| super(); | ||
| this.address = address; | ||
| this.key = key; | ||
| this.pack = pack; | ||
| this.isClose = false; | ||
| this.maxRelinkCount = 20; | ||
| this.isLinking = false; | ||
| this.linkOutTime = 200; | ||
| this.relinkCount = 0; | ||
| this.handle = new RPCHandle({ | ||
| close: () => { | ||
| this.clear(); | ||
| this.isLinking = false; | ||
| }, | ||
| send: (body) => { | ||
| this.send(body); | ||
| } | ||
| }, this); | ||
| } | ||
| set owner(value) { | ||
| this.handle.target = value; | ||
| } | ||
| getKey() { | ||
| return this.key; | ||
| } | ||
| ping() { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| return yield this.rs.ping(); | ||
| }); | ||
| } | ||
| link() { | ||
| if (!this.isLinking) { | ||
| this.isLinking = true; | ||
| console.log("正在连接" + this.address); | ||
| this.ws = new ws_1.default(this.address, { handshakeTimeout: 2000 }); | ||
| this.ws.addEventListener("message", (evt) => { | ||
| let obj; | ||
| try { | ||
| obj = this.pack.parse(evt.data); | ||
| } | ||
| catch (_a) { | ||
| console.warn("RPCClient: can't parse for data"); | ||
| } | ||
| this.receive(obj); | ||
| }); | ||
| this.ws.addEventListener("close", () => { | ||
| this.reset(); | ||
| }); | ||
| this.ws.addEventListener("error", (event) => { | ||
| console.warn(event); | ||
| this.reset(); | ||
| }); | ||
| this.ws.addEventListener("open", () => { | ||
| this.emit("open"); | ||
| this.relinkCount = 0; | ||
| this.linkOutTime = 200; | ||
| }); | ||
| } | ||
| } | ||
| reset() { | ||
| this.emit("reset"); | ||
| this.clear(); | ||
| this.isLinking = false; | ||
| if (this.maxRelinkCount > this.relinkCount && !this.isClose) { | ||
| this.linkOutTime *= 1.5; | ||
| this.relinkCount++; | ||
| setTimeout(() => { | ||
| this.link(); | ||
| this.emit("relink"); | ||
| }, this.linkOutTime); | ||
| } | ||
| else { | ||
| this.emit("stop"); | ||
| } | ||
| } | ||
| clear() { | ||
| if (this.ws) { | ||
| this.ws.removeAllListeners("message"); | ||
| this.ws.removeAllListeners("close"); | ||
| this.ws.removeAllListeners("error"); | ||
| this.ws.removeAllListeners("open"); | ||
| } | ||
| } | ||
| close() { | ||
| if (this.ws) { | ||
| this.isClose = true; | ||
| this.ws.close(); | ||
| } | ||
| else { | ||
| console.log("RPCClient: no ws"); | ||
| } | ||
| } | ||
| send(body) { | ||
| if (this.ws) { | ||
| let value = null; | ||
| try { | ||
| value = this.pack.stringify(body); | ||
| } | ||
| catch (e) { | ||
| console.warn("RPCClient: can't stringify " + e); | ||
| } | ||
| if (value != null) { | ||
| this.ws.send(value); | ||
| } | ||
| else { | ||
| console.log("RPCClient: can't send null"); | ||
| } | ||
| } | ||
| else { | ||
| console.warn("RPCClient: no ws"); | ||
| } | ||
| } | ||
| get rs() { | ||
| return this.handle.rs; | ||
| } | ||
| receive(body) { | ||
| this.handle.receive(body); | ||
| } | ||
| error(value) { | ||
| this.handle.error(value); | ||
| } | ||
| } | ||
| exports.RPCClient = RPCClient; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
-337
| import { ZeroDispatcher } from "zero-mvc" | ||
| import ZeroRemote, { IChannel, IPack, jsonPack, LiteStack, Visitor } from "." | ||
| import WebSocket from "ws" | ||
| export enum RPCCode { | ||
| INITIATIVE = 0, | ||
| FAIL = 1, | ||
| CALLBACK = 50, | ||
| SUCCESS = 200, | ||
| KICK = 30, | ||
| } | ||
| interface IChannelVO { | ||
| code: RPCCode.INITIATIVE | RPCCode.SUCCESS | ||
| key: string, | ||
| args: any[] | ||
| cbs: { [key: number]: number } | ||
| index: number | ||
| } | ||
| interface IChannelCbVO { | ||
| code: RPCCode.CALLBACK | ||
| key: number, | ||
| args: any[] | ||
| } | ||
| interface IChannelErrVO { | ||
| code: RPCCode.FAIL | ||
| key?: number, | ||
| error?: number | string | ||
| } | ||
| interface IChannelKickVO { | ||
| code: RPCCode.KICK | ||
| } | ||
| export type IRPCProto = IChannelErrVO | IChannelCbVO | IChannelVO | IChannelKickVO | ||
| export type IRSC<T> = { [P in keyof T]: (...args: any) => any } | ||
| export type IRSP<T> = { [P in keyof T]: IRS<T[P]> } | ||
| export type IRS<T extends IRSC<T>> = { [P in keyof T]: (...args: Parameters<T[P]>) => Promise<ReturnType<T[P]>> } | ||
| class RPCHandle<T = any> { | ||
| static callbackMaxStack = 20 | ||
| rs: T | ||
| public target: object | null = null | ||
| private callbackStack = new LiteStack<{ resolve: Function, reject?: Function }>() | ||
| constructor(public carer: IChannel<IRPCProto>, public owner: object) { | ||
| let k: string | ||
| let f = (...args: T[]) => { | ||
| return new Promise((resolve: (value: any) => void, reject: () => void) => { | ||
| let cbs: { [key: number]: number } = {} | ||
| args.forEach((arg, index) => { | ||
| if (typeof arg == "function") { | ||
| cbs[index] = this.callbackStack.push({ resolve: arg }) | ||
| } | ||
| }) | ||
| this.carer.send({ | ||
| code: RPCCode.INITIATIVE, | ||
| key: k, | ||
| args: args, | ||
| cbs: cbs, | ||
| index: this.callbackStack.push({ resolve: resolve, reject: reject }), | ||
| }) | ||
| if (this.callbackStack.size > RPCHandle.callbackMaxStack) { | ||
| this.callbackStack.clear(RPCHandle.callbackMaxStack / 2) | ||
| } | ||
| }) | ||
| } | ||
| this.rs = new Proxy({} as any, { | ||
| get: (target: any, p: string, receiver: any) => { | ||
| k = p | ||
| return f | ||
| } | ||
| }) | ||
| } | ||
| receive(body: IRPCProto): void { | ||
| if (body.code == RPCCode.INITIATIVE || body.code == RPCCode.SUCCESS) { | ||
| let target | ||
| if (this.target && (this.target as any)[body.key] != null) { | ||
| target = this.target | ||
| } else if ((this.owner as any)[body.key] == null) { | ||
| target = this.target | ||
| } else { | ||
| target = this.owner | ||
| } | ||
| if (target == null) { | ||
| this.reject(body.index, "no remote traget " + body.key) | ||
| } else { | ||
| let method = ((target as any)[body.key] as Function) | ||
| if (method) { | ||
| if (body.cbs) { | ||
| for (const key in body.cbs) { | ||
| if (body.cbs.hasOwnProperty(key)) { | ||
| const element = body.cbs[key]; | ||
| body.args[key] = (...CbArgs: any[]) => { | ||
| this.carer.send({ | ||
| code: RPCCode.CALLBACK, | ||
| key: element, | ||
| args: CbArgs | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Promise.resolve(method.apply(target, body.args || [])).then((value) => { | ||
| this.carer.send({ | ||
| code: RPCCode.CALLBACK, | ||
| key: body.index, | ||
| args: [value] | ||
| }) | ||
| }).catch(err => { | ||
| console.log(err); | ||
| }) | ||
| } else { | ||
| this.reject(body.index, "no remote method " + body.key) | ||
| } | ||
| } | ||
| } else if (body.code == RPCCode.CALLBACK) { | ||
| let method = this.callbackStack.pull(body.key) | ||
| if (method) { | ||
| method.resolve.apply(null, body.args); | ||
| } else { | ||
| this.error() | ||
| } | ||
| body.args | ||
| } else if (body.code == RPCCode.FAIL) { | ||
| if (body.key != null) { | ||
| let method = this.callbackStack.pull(body.key) | ||
| if (method && method.reject) { | ||
| method.reject(body.error); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| error(value?: number | string) { | ||
| this.carer.send({ | ||
| code: RPCCode.FAIL, | ||
| error: value, | ||
| }) | ||
| } | ||
| reject(key: number, value?: string) { | ||
| this.carer.send({ | ||
| code: RPCCode.FAIL, | ||
| key: key, | ||
| error: value, | ||
| }) | ||
| } | ||
| } | ||
| /** | ||
| * RPC模式下的用户 | ||
| * 回调函数在第没有被调用的情况下会被回收 | ||
| */ | ||
| export class RPCVisitor<T extends IRSC<T> = any> extends Visitor<IRPCProto, IRPCProto> { | ||
| handle!: RPCHandle | ||
| key: string | null = null | ||
| static remotePool: { [key: string]: (rs: RPCVisitor) => Promise<void> } = {}; | ||
| set owner(value: any) { | ||
| this.handle.target = value | ||
| } | ||
| constructor(carer: IChannel<IRPCProto>, server: ZeroRemote) { | ||
| super(carer, server); | ||
| this.handle = new RPCHandle(carer, this) | ||
| this.handle.rs.getKey().then((key: string) => { | ||
| this.key = key | ||
| let callback = RPCVisitor.remotePool[key] | ||
| if (callback) { | ||
| callback(this).catch((err: any) => { | ||
| console.warn(err) | ||
| }) | ||
| } else { | ||
| console.log("主没上没有命名为\"" + key + "\"的的RPC服务") | ||
| } | ||
| }).catch((err: any) => { | ||
| console.log(err, "rpc error") | ||
| }) | ||
| } | ||
| /** | ||
| * RemoteServer | ||
| * 远程服务 | ||
| */ | ||
| get rs(): IRS<T> { | ||
| return this.handle.rs | ||
| } | ||
| static addRemote<T extends IRSC<T> = any>(callback: (rs: RPCVisitor<T>) => Promise<void>, key: string = "") { | ||
| RPCVisitor.remotePool[key] = callback | ||
| } | ||
| ping(): boolean { | ||
| return true | ||
| } | ||
| error(value?: number | string) { | ||
| this.handle.error(value) | ||
| } | ||
| receive(body: IRPCProto): void { | ||
| this.handle.receive(body) | ||
| } | ||
| clear() { | ||
| } | ||
| } | ||
| /** | ||
| * RPC模式 客户端 | ||
| * 支持 双向 添加回调函数 | ||
| * 支持返回值 | ||
| * 支持智能提示 | ||
| * 支持一对多 | ||
| */ | ||
| export class RPCClient<T extends IRSC<T> = any> extends ZeroDispatcher<{ | ||
| stop: [] | ||
| open: [] | ||
| relink: [] | ||
| reset: [] | ||
| }> { | ||
| public ws!: WebSocket | ||
| private isClose = false | ||
| public maxRelinkCount = 20 | ||
| private isLinking = false | ||
| private handle: RPCHandle<IRS<T>> | ||
| private linkOutTime: number = 200 | ||
| private relinkCount = 0 | ||
| set owner(value: any) { | ||
| this.handle.target = value | ||
| } | ||
| constructor(private address: string, public key: string = "", public pack: IPack = jsonPack) { | ||
| super() | ||
| this.handle = new RPCHandle({ | ||
| close: () => { | ||
| this.clear() | ||
| this.isLinking = false | ||
| }, | ||
| send: (body) => { | ||
| this.send(body) | ||
| } | ||
| }, this) | ||
| } | ||
| getKey() { | ||
| return this.key | ||
| } | ||
| async ping(): Promise<boolean> { | ||
| return await (this.rs as any).ping() | ||
| } | ||
| link(): void { | ||
| if (!this.isLinking) { | ||
| this.isLinking = true | ||
| console.log("正在连接" + this.address) | ||
| this.ws = new WebSocket(this.address, { handshakeTimeout: 2000 }) | ||
| this.ws.addEventListener("message", (evt: { data: any }) => { | ||
| let obj: any; | ||
| try { | ||
| obj = this.pack.parse(evt.data); | ||
| } | ||
| catch { | ||
| console.warn("RPCClient: can't parse for data"); | ||
| } | ||
| this.receive(obj); | ||
| }); | ||
| this.ws.addEventListener("close", () => { | ||
| this.reset() | ||
| }); | ||
| this.ws.addEventListener("error", (event) => { | ||
| console.warn(event) | ||
| this.reset() | ||
| }); | ||
| this.ws.addEventListener("open", () => { | ||
| this.emit("open") | ||
| this.relinkCount = 0 | ||
| this.linkOutTime = 200 | ||
| }); | ||
| } | ||
| } | ||
| reset() { | ||
| this.emit("reset") | ||
| this.clear() | ||
| this.isLinking = false | ||
| if (this.maxRelinkCount > this.relinkCount && !this.isClose) { | ||
| this.linkOutTime *= 1.5 | ||
| this.relinkCount++ | ||
| setTimeout(() => { | ||
| this.link() | ||
| this.emit("relink") | ||
| }, this.linkOutTime); | ||
| } else { | ||
| this.emit("stop") | ||
| } | ||
| } | ||
| clear() { | ||
| if (this.ws) { | ||
| this.ws.removeAllListeners("message"); | ||
| this.ws.removeAllListeners("close"); | ||
| this.ws.removeAllListeners("error"); | ||
| this.ws.removeAllListeners("open"); | ||
| } | ||
| } | ||
| close() { | ||
| if (this.ws) { | ||
| this.isClose = true | ||
| this.ws.close(); | ||
| } else { | ||
| console.log("RPCClient: no ws"); | ||
| } | ||
| } | ||
| send(body: IRPCProto) { | ||
| if (this.ws) { | ||
| let value: any = null; | ||
| try { | ||
| value = this.pack.stringify(body) | ||
| } catch (e) { | ||
| console.warn("RPCClient: can't stringify " + e) | ||
| } | ||
| if (value != null) { | ||
| this.ws.send(value); | ||
| } | ||
| else { | ||
| console.log("RPCClient: can't send null") | ||
| } | ||
| } else { | ||
| console.warn("RPCClient: no ws") | ||
| } | ||
| } | ||
| get rs() { | ||
| return this.handle.rs | ||
| } | ||
| receive(body: IRPCProto): void { | ||
| this.handle.receive(body) | ||
| } | ||
| error(value?: number | string) { | ||
| this.handle.error(value) | ||
| } | ||
| } |
-7
| // interface T1 { | ||
| // fuck: (value: { a: number, b: Function }) => number | ||
| // } | ||
| export interface T2 { | ||
| getPid: () => number; | ||
| tt: (message: string) => void; | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1
-75%1
-50%25143
-78.96%8
-52.94%563
-83.11%1
Infinity%+ Added
+ Added
- Removed
- Removed