123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /** @format */
- import {Data, GameControl, Mgr} from '../GameControl'
- import {Log} from '../utils/LogUtils'
- import {EVENT, GAME_TYPE, LANGUAGE_TYPE} from '../enums/Enum'
- import {MSG} from '../enums/MSG'
- import {ProtoUtils} from '../proto/ProtoUtils'
- import {msgCmd} from '../proto/msg_cmd'
- import {ConstValue} from '../data/ConstValue'
- import {UI} from '../enums/UI'
- export class SendPackage {
- public type: number | string = 0
- public content: any = {}
- public showLoading: boolean = true
- public test?: boolean = false
- public errno?: number
- public handleErr?: boolean
- }
- export class NetManager {
- // webSocket连接
- public webSocket: WebSocket = null
- // 消息业务类型
- private msgType: Map<string, any> = new Map<string, any>()
- // 消息业务类型
- private msgList: Map<number, any> = new Map<number, any>()
- // 重连设定
- private autoReconnect: number = 3 // 0 不自动重连,其他正整数为自动重试次数
- // 记录当前等待返回的所有showLoading的key
- private showLoadingMap: Map<string, SendPackage> = new Map<string, SendPackage>()
- private _url: string = 'ws://192.168.31.100:8001'
- public get url(): string {
- return this._url
- }
- public set url(value: string) {
- this._url = value
- }
- private reTryFailCallBack: Function = null
- private timeOutCallBack: Function = null
- private maintainCallBack: Function = null
- private kickOffCallBack: Function = null
- private timeOutID: any = null // 接收数据定时器
- private timeOutTime: number = 10000 // 超时时间 达到会主动关闭连接
- private keepAliveID: any = null // 心跳定时器
- private keepAliveTime: number = 5000 // 心跳间隔 心跳间隔必须小于超时时间
- private serverTimeID: any = null // 服务器时间定时器
- private reConnectTime: number = 2000 // 重连间隔
- private curAutoReconnect: number = 0 // 当前重连次数
- private isMaxReconnect: boolean = true
- public init() {
- let reLogin = () => {
- Mgr.ui.hideLoading()
- Mgr.ui.message(
- LANGUAGE_TYPE.netCut,
- () => {
- GameControl.resetGame()
- },
- true,
- )
- }
- this.setReTryFailCallback(reLogin)
- this.setTimeOutCallback(reLogin)
- }
- public reset() {
- this.clearLoading()
- this.close()
- Data.main.webSocketCon = false
- }
- // 设置重试失败回调
- public setReTryFailCallback(reTryFailCallBack: Function) {
- this.reTryFailCallBack = reTryFailCallBack
- }
- // 设置超时回调
- public setTimeOutCallback(timeOutCallBack: Function) {
- this.timeOutCallBack = timeOutCallBack
- }
- // 设置维护回调
- public setMaintainCallback(maintainCallBack: Function) {
- this.maintainCallBack = maintainCallBack
- }
- // 设置被踢回调
- public setKickOffCallback(kickOffCallBack: Function) {
- this.kickOffCallBack = kickOffCallBack
- }
- public reg(keyName: string, id: number, protoType) {
- this.msgType.set(this.getKey(id), {id, keyName, protoType})
- }
- public getKey(id: number) {
- return msgCmd[id]
- }
- public add(id: number, caller: any, listener: Function, ...argArray: any[]) {
- Mgr.event.add(this.getKey(id), caller, listener, argArray)
- }
- public addTop(id: number, caller: any, listener: Function, ...argArray: any[]) {
- Mgr.event.addTop(this.getKey(id), caller, listener, argArray)
- }
- public addOnce(id: number, caller: any, listener: Function, ...argArray: any[]) {
- Mgr.event.addOnce(this.getKey(id), caller, listener, argArray)
- }
- public del(id: number, caller: any, listener: Function) {
- Mgr.event.remove(this.getKey(id), caller, listener)
- }
- public connect() {
- this.close()
- try {
- if (Mgr.platform.isAndroid()) {
- // @ts-ignore
- this.webSocket = new WebSocket(this.url, null, cc.url.raw('resources/ssl/cacert.pem'))
- } else {
- this.webSocket = new WebSocket(this.url)
- }
- console.log('connect WebSocket:', this.url)
- this.webSocket.binaryType = 'arraybuffer'
- this.webSocket.onopen = this.onOpen.bind(this)
- this.webSocket.onmessage = this.onMessage.bind(this)
- this.webSocket.onerror = this.onError.bind(this)
- this.webSocket.onclose = this.onClose.bind(this)
- } catch (e) {
- console.error('connect WebSocket err:', e)
- }
- }
- public close() {
- Log.net('close')
- this.stopKeepAlive()
- if (this.webSocket && this.webSocket.readyState == WebSocket.OPEN) {
- this.webSocket.onopen = null
- this.webSocket.onmessage = null
- this.webSocket.onerror = null
- this.webSocket.onclose = null
- this.webSocket.close()
- Mgr.event.trigger(EVENT.webSocketClose)
- } else {
- Log.warn('close err: this.webSocket is null or is not OPEN')
- }
- }
- public sendKeepAlive() {
- if (this.keepAliveID !== null) {
- clearTimeout(this.keepAliveID)
- }
- this.keepAliveID = setTimeout(this.keepAlive.bind(this), this.keepAliveTime)
- }
- public stopKeepAlive() {
- if (this.timeOutID !== null) {
- clearTimeout(this.timeOutID)
- }
- if (this.keepAliveID !== null) {
- clearTimeout(this.keepAliveID)
- }
- }
- private keepAlive() {
- this.send(msgCmd.cmd_ping, null, false)
- if (this.timeOutID !== null) {
- clearTimeout(this.timeOutID)
- }
- this.timeOutID = setTimeout(this.aliveTimeOut.bind(this), this.timeOutTime)
- }
- private aliveTimeOut() {
- Log.net('心跳消息超时,链接断开')
- this.close()
- this.timeOutCallBack && this.timeOutCallBack()
- }
- private sendData(data: SendPackage, isTest: boolean = false) {
- if (data) {
- let key = typeof data.type == 'number' ? this.getKey(data.type) : data.type
- //临时将协议number改成协议string
- data.type = key.replace('cmd_', '')
- if (key != msgCmd[msgCmd.cmd_ping] && data.showLoading) {
- //Mgr.ui.showLoading(LANGUAGE_TYPE.loading, true, false)
- this.showLoadingMap.set(key, data)
- }
- if (isTest) {
- Log.net('testSend ->', key, '\n', data.content)
- let testResp = {data: JSON.stringify(data)}
- this.onMessage(testResp)
- } else {
- //this.webSocket.send(JSON.stringify(data))
- let bytes = ProtoUtils.Encode(data.type, data.content)
- let buffer = new ArrayBuffer(4 + bytes.byteLength)
- new DataView(buffer).setInt32(0, msgCmd[key])
- new Uint8Array(buffer, 4).set(new Uint8Array(bytes))
- this.webSocket.send(new Uint8Array(buffer))
- if (key != msgCmd[msgCmd.cmd_ping]) {
- Log.net('send ->', key, '\n', data.content)
- }
- }
- }
- }
- /**
- *
- * @param key 协议key
- * @param data 要发送的数据
- * @param showLoading 是否显示响应保护
- */
- public send(id: number, data: any = null, showLoading: boolean = true, handleErr: boolean = false) {
- let test = false
- if (data && data.test) {
- test = data.test
- delete data.test
- }
- if (this.webSocket && this.webSocket.readyState === WebSocket.OPEN) {
- this.sendData({type: this.getKey(id), content: data, showLoading}, test)
- }
- }
- public getSendPackage(id: number, data: any = null, showLoading: boolean = true): SendPackage {
- let newPackage = new SendPackage()
- newPackage.type = this.getKey(id)
- newPackage.content = data
- newPackage.showLoading = showLoading
- return newPackage
- }
- public sendEx(sendList: SendPackage[], overCallback: Function) {
- let batchKey = new Date().getTime()
- let batchUnit: any = {}
- batchUnit.sendList = sendList
- batchUnit.retList = new Map<string, any>()
- for (let i = 0; i < sendList.length; i++) {
- batchUnit.retList.set(sendList[i].type, null)
- }
- batchUnit.overCallback = overCallback
- this.msgList.set(batchKey, batchUnit)
- this.tryStepSendEx()
- }
- public tryStepSendEx(key = null, ret = null) {
- let msgListKeys = this.msgList.keysArr()
- if (msgListKeys.length > 0) {
- let batchUnit = this.msgList.get(msgListKeys[0])
- if (!batchUnit) return
- if (key && batchUnit.retList.get(key) !== undefined) {
- batchUnit.retList.set(key, ret)
- if (ret > 0) {
- //先执行delete,如果overCallback中有sendEx会插入一段overCallback,导致overCallback执行两次
- this.msgList.delete(msgListKeys[0])
- if (batchUnit.overCallback) {
- batchUnit.overCallback(false)
- }
- return
- }
- }
- let data = batchUnit.sendList.shift()
- if (data) {
- let test = false
- if (data.test) {
- test = data.test
- delete data.test
- }
- this.sendData(data, test)
- } else {
- //先执行delete,如果overCallback中有sendEx会插入一段overCallback,导致overCallback执行两次
- this.msgList.delete(msgListKeys[0])
- if (batchUnit.overCallback) {
- batchUnit.overCallback(true)
- }
- }
- }
- }
- public encode(key: any, data: any) {}
- public decode(data): any {}
- private onOpen(event) {
- Log.net('onOpen')
- Mgr.event.trigger(EVENT.webSocketOpen)
- this.sendKeepAlive()
- this.curAutoReconnect = 0
- }
- private onClose(event) {
- Log.net('onClose event:', event)
- setTimeout(this.reConnect.bind(this), this.reConnectTime)
- Mgr.event.trigger(EVENT.webSocketClose)
- }
- public reConnect() {
- // 开始自动重连
- if (this.autoReconnect <= 0) return
- if (this.isMaxReconnect) this.curAutoReconnect += 1
- if (this.curAutoReconnect < this.autoReconnect) {
- this.connect()
- } else {
- if (this.reTryFailCallBack) {
- this.reTryFailCallBack()
- }
- }
- }
- public stopReConnect() {
- this.autoReconnect = 0
- }
- public setReConnect() {
- this.autoReconnect = 4
- }
- private onMessage(evt: any) {
- let {data} = evt
- //let obj = JSON.parse(data)
- let type = new DataView(data).getInt32(0)
- let content = ProtoUtils.Decode(msgCmd[type], new Uint8Array(data.slice(4)))
- this.msgTrigger({showLoading: false, type, content, errno: content.errno})
- // try {
- // this.msgTrigger(obj)
- // } catch (e) {
- // console.error('websocket onMessage', e)
- // }
- }
- public msgTrigger(object: SendPackage) {
- if (object) {
- let key = typeof object.type == 'number' ? this.getKey(object.type) : 'cmd_' + object.type
- if (key != msgCmd[msgCmd.cmd_ping_rsp]) {
- Log.net('onMessage Resp ->', key, object)
- } else {
- this.sendKeepAlive()
- }
- let sendKey = key.replace('_rsp', '')
- this.tryStepSendEx(sendKey, object.errno)
- this.showLoadingMap.delete(sendKey)
- if (this.showLoadingMap.size == 0) {
- //Mgr.ui.hideLoading()
- }
- //处理心跳
- if (key == msgCmd[msgCmd.cmd_ping_rsp]) {
- if (object.content.time != Data.main.serverTime && Data.main.loginTime) {
- Data.main.serverTime = object.content.time
- Data.main.secondTime = Data.main.serverTime - Data.main.loginTime
- Data.main.globalTime = Data.main.secondTime
- Data.main.minutesTime = Math.floor(Data.main.secondTime / 60)
- Mgr.time.globalTimer()
- }
- }
- //处理异常
- else if (key == msgCmd[msgCmd.cmd_exception_nty]) {
- this.stopReConnect()
- Mgr.ui.message(
- Mgr.i18n.getLabel('e' + object.errno.toString()),
- () => {
- GameControl.resetGame()
- },
- true,
- )
- }
- //处理普通消息
- else {
- if (!object.errno || object.handleErr) {
- let isTrigger = Mgr.event.trigger(key, object.content, Data.main.rewardNtyMap.get(key))
- if (!isTrigger) Log.warn('Not Found Resp callback reg!', key)
- } else {
- Mgr.ui.tip(Mgr.i18n.getLabel('e' + object.errno.toString()))
- }
- }
- Data.main.rewardNtyMap.delete(key)
- }
- }
- /**
- * 处理服务器踢人通知
- */
- private kickOffNty(data: any) {
- console.info('server kick off!')
- if (this.kickOffCallBack) {
- this.kickOffCallBack(data)
- }
- }
- private onError(event) {
- console.error('websocket onError', event)
- }
- private clearLoading() {
- this.showLoadingMap.clear()
- }
- }
|