147 lines
4.9 KiB
TypeScript
147 lines
4.9 KiB
TypeScript
|
import { ApiReturn, WsClient } from "tsrpc-browser";
|
||
|
import { ServiceType } from "../shared/protocols/serviceProto_public";
|
||
|
import { NetUtil } from "./NetUtil";
|
||
|
|
||
|
export class WebsocketClient {
|
||
|
public static EVENT_DISCONNECTED = 'WebsocketClient.EVENT_DISCONNECTED';
|
||
|
protected _conn: WsClient<ServiceType> = null;
|
||
|
protected _serverUrl = '';
|
||
|
protected _eventHandlers: { [key: string]: { event: string, func: Function, thisArg: any }[] } = {};
|
||
|
|
||
|
protected _handlers: { msg: string, func: Function, handler: Function, thisArg: any }[] = [];
|
||
|
|
||
|
public get conn(): WsClient<ServiceType> {
|
||
|
return this._conn;
|
||
|
}
|
||
|
|
||
|
createConnection(serverUrls: Readonly<string[]>) {
|
||
|
if (this._conn) {
|
||
|
this._conn.disconnect(1000, 'switch_server');
|
||
|
}
|
||
|
let index = Math.floor(serverUrls.length * Math.random());
|
||
|
let serverUrl = serverUrls[index];
|
||
|
this._serverUrl = serverUrl;
|
||
|
this._conn = NetUtil.createWebsocketClient(this._serverUrl);
|
||
|
|
||
|
this._conn.flows.postDisconnectFlow.push(v => {
|
||
|
this._dispatchEvent(WebsocketClient.EVENT_DISCONNECTED, v);
|
||
|
return v;
|
||
|
});
|
||
|
|
||
|
/*
|
||
|
this._conn.flows.postRecvMsgFlow.push(v=>{
|
||
|
console.log(v.msgName,v.msg);
|
||
|
return v;
|
||
|
});
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
on(event: string, func: Function, thisArg?: any) {
|
||
|
let handler = func;
|
||
|
if (thisArg) {
|
||
|
handler = func.bind(thisArg);
|
||
|
}
|
||
|
let handlers = this._eventHandlers[event] || [];
|
||
|
handlers.push({ event: event, func: func, thisArg: thisArg });
|
||
|
this._eventHandlers[event] = handlers;
|
||
|
}
|
||
|
|
||
|
off(event: string, func?: Function, thisArg?: any) {
|
||
|
let handlers = this._eventHandlers[event];
|
||
|
if (handlers) {
|
||
|
for (let i = 0; i < handlers.length; ++i) {
|
||
|
let item = handlers[i];
|
||
|
if (item.func === func && item.thisArg == thisArg) {
|
||
|
handlers.splice(i, 1);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private _dispatchEvent(event: string, args) {
|
||
|
let handlers = this._eventHandlers[event];
|
||
|
if (handlers) {
|
||
|
for (let i = 0; i < handlers.length; ++i) {
|
||
|
let item = handlers[i];
|
||
|
item.func.call(item.thisArg, args);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
startPing() {
|
||
|
setInterval(() => {
|
||
|
if (this._conn.isConnected) {
|
||
|
//console.log('ping');
|
||
|
this._conn.sendMsg('Ping', {});
|
||
|
}
|
||
|
}, 5000);
|
||
|
}
|
||
|
|
||
|
public get serverUrl(): string {
|
||
|
return this._serverUrl;
|
||
|
}
|
||
|
|
||
|
public listenMsg<T extends keyof ServiceType['msg']>(msgName: T | RegExp, func: Function, thisArg?: any) {
|
||
|
let handler = func;
|
||
|
if (thisArg) {
|
||
|
handler = func.bind(thisArg);
|
||
|
}
|
||
|
// console.log("添加监听 001",this._handlers);
|
||
|
// console.log("添加监听 002",this._conn);
|
||
|
this._handlers.push({ msg: msgName as string, func: func, handler: handler, thisArg: thisArg });
|
||
|
this._conn.listenMsg(msgName, handler as any);
|
||
|
}
|
||
|
|
||
|
public unlistenMsg<T extends keyof ServiceType['msg']>(msgName: T | RegExp, func: Function, thisArg?: any) {
|
||
|
for (let i = 0; i < this._handlers.length; ++i) {
|
||
|
let item = this._handlers[i];
|
||
|
if (item.msg === msgName && item.func === func || item.thisArg == thisArg) {
|
||
|
// console.log("移除监听前 001====", item);
|
||
|
this._handlers.splice(i, 1);
|
||
|
this._conn.unlistenMsg(msgName, item.handler);
|
||
|
item = null;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
console.log("移除监听后 002====", this._handlers);
|
||
|
}
|
||
|
|
||
|
public unlistenMsgAll<T extends keyof ServiceType['msg']>(msgName: T | RegExp): void {
|
||
|
for (let i = this._handlers.length - 1; i >= 0; --i) {
|
||
|
let item = this._handlers[i];
|
||
|
if (item.msg === msgName) {
|
||
|
this._handlers.splice(i, 1);
|
||
|
}
|
||
|
}
|
||
|
this._conn.unlistenMsgAll(msgName);
|
||
|
console.log("移除监听后", this._handlers);
|
||
|
}
|
||
|
|
||
|
public callApi<T extends string & keyof ServiceType['api']>(apiName: T, req: ServiceType['api'][T]['req'], options?: any): Promise<ApiReturn<ServiceType['api'][T]['res']>> {
|
||
|
return this._conn.callApi(apiName, req, options);
|
||
|
}
|
||
|
|
||
|
public async ensureConnected() {
|
||
|
let ret = await this._connect();
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
disconnect() {
|
||
|
this._conn.disconnect();
|
||
|
}
|
||
|
|
||
|
private async _connect(): Promise<{ isSucc: boolean, err?: {code?:string, message: string } }> {
|
||
|
// Connect
|
||
|
let resConnect = await this._conn.connect();
|
||
|
if (!resConnect.isSucc) {
|
||
|
return { isSucc: false, err: { message: resConnect.errMsg } };
|
||
|
}
|
||
|
|
||
|
return { isSucc: true };
|
||
|
}
|
||
|
|
||
|
public get subRoomDisplayName() {
|
||
|
return this.subRoomDisplayName;
|
||
|
}
|
||
|
}
|