Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

zero-remote

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zero-remote - npm Package Compare versions

Comparing version
1.2.0
to
1.2.1
+295
ZeroRemoteClient.ts
import WebSocket from "ws";
import ZeroDispatcher from "./ZeroDispatcher";
import { IPack, jsonPack, PromiseSender, Receiver, ISCMessage, ReportCode } from "./IZeroRomeote";
/**
* 错误错误会弹窗
* 重连多次后会弹窗
*/
/**
* 与后端协议
* 所有数据以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;
relinkTimeOut?: any;
private pingTimeStart!: Date;
pingTime: number = 0;
private _mask: number = 0;
private isMask: boolean = false;
public get mask(): number {
return this._mask;
}
public set mask(value: number) {
let isMask = value > 0
if (this.isMask != isMask) {
this.isMask = isMask;
if (isMask) {
this.emit("showMask");
} else {
this.emit("hideMask");
}
}
}
constructor(public url: string) {
super();
setInterval(() => {
if (this.isOpen) {
if (this.pingIndex == this.heartbeatTime + this.outTime) {
this.mask++
} else if (this.pingIndex == this.heartbeatTime) {
this.pingTimeStart = new Date();
this.ws.send(this.pack.stringify({ data: this.pingTime }));
}
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 {
// pingTimeStart()
// this.pingTime = new Date()
this.pingTime = new Date().getTime() - this.pingTimeStart.getTime();
}
} 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--
}
/**
* 这个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 = 0
this.relinkCount = 0;
this.isOpen = true;
this.emit("linked");
if (callback) {
callback();
}
};
this.ws.onclose = () => {
this.mask = 0;
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();
}
}
+1
-1
{
"name": "zero-remote",
"version": "1.2.0",
"version": "1.2.1",
"description": "常连接网络",

@@ -5,0 +5,0 @@ "main": "dist/index.js",