1. 程式人生 > >使用cocoscreator + node.js + websocket實現簡單的聊天服務

使用cocoscreator + node.js + websocket實現簡單的聊天服務

先上個效果圖:

使用cocoscreator 1.9.1 + node.js + websocket實現,沒有使用socket.io, 全部自己封裝,長連線進行封裝後可以和短連線使用方法一樣,使用簡單,方便以後開發網路遊戲。

1、客戶端:

  主要就是聊天內容的顯示,自動換行和背景擴充套件,程式碼大概如下:

cc.Class({
    extends: cc.Component,

    properties: {
        msgLabel: cc.Label,
        uidLabel: cc.Label,
        msgLayout: cc.Layout,
        msgBg: cc.Node,
        maxLen: 500,
    },

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {},

    start () {
        this.node.runAction(cc.fadeTo(0.5, 255))
    },

    initMsg(msg, uid){
        this.msgLabel.string = msg;
        this.uidLabel.string = uid;

        this.msgLabel.overflow = cc.Label.Overflow.NONE;
        // this.msgBg.width = this.msgLabel.node.width + 10;
        // this.msgBg.height = this.msgLabel.node.height + 10;
        // this.node.height = this.msgBg.height + 40;

        this.scheduleOnce((dt)=>{
            if ( this.msgLabel.node.width >= this.maxLen){
                this.msgLabel.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
                this.msgLabel.node.width = this.maxLen;
            }

            this.msgBg.width = this.msgLabel.node.width + 10;
            this.msgBg.height = this.msgLabel.node.height + 10;
            this.node.height = this.msgBg.height + 40;

        }, 0);

        this.node.opacity = 0;
    }

    // update (dt) {},
});

  網路部分分成了四層:

    1、socket 封裝基礎的websocket, 這裡是最底層,也是真正連結的開始

    2、network 控制socket連結層,實現各回調介面

    3、netproxy 封裝各服務功能,把長連線變成短連線的請求方式

    4、netprotocols 和伺服器協商,確定每個請求的請求體格式和回覆格式

  各部分程式碼如下:

  GameWebSocket.js:  

/**
 * @enum {number}
 */
var GameWebSocketState = cc.Enum({
    CONNECTING: 1,
    OPEN: 
2, CLOSING: 3, CLOSED: 4 }); /** * @interface */ var GameWebSocketDelegate = cc.Class({ onSocketOpen: function () { }, /** * 收到了訊息 * @param {string|Uint8Array} data */ onSocketMessage: function (data) { }, onSocketError: function () { }, /*
* * 連線關閉 * @param {string} reason */ onSocketClosed: function (reason) { } }); /** * @interface */ var GameWebSocketInterface = cc.Class({ connect: function () { }, send: function () { }, close: function () { }, getState: function () { } }); var GameWebSocket = cc.Class({ extends: GameWebSocketInterface, properties: { /** * @type {String} 伺服器地址 */ _address: null, /** * @type {GameWebSocketDelegate} */ _delegate: null, /** * @type {WebSocket} */ _webSocket: null, }, /** * @param {string} address 伺服器地址 * @param {GameWebSocketDelegate} delegate 回撥介面 */ init: function(address, delegate){ this._address = address; this._delegate = delegate; this._webSocket = null; }, connect: function () { cc.log('connect to '+ this._address); var ws = this._webSocket = new WebSocket(this._address); ws.onopen = this._delegate.onSocketOpen.bind(this._delegate); ws.onmessage = function (param) { this._delegate.onSocketMessage(param.data); }.bind(this); ws.onerror = this._delegate.onSocketError.bind(this._delegate); // function({code: Number, reason: String, wasClean: Boolean})} ws.onclose = function (param) { this._delegate.onSocketClosed(param.reason); }.bind(this); }, /** * 傳送資料 * @param {string|Uint8Array} stringOrBinary */ send: function (stringOrBinary) { this._webSocket.send(stringOrBinary); }, close: function () { if (!this._webSocket) { return; } try { this._webSocket.close(); } catch (err) { cc.log('error while closing webSocket', err.toString()); } this._webSocket = null; }, getState: function () { if (this._webSocket) { switch(this._webSocket.readyState){ case WebSocket.OPEN: return GameWebSocketState.OPEN; case WebSocket.CONNECTING: return GameWebSocketState.CONNECTING; case WebSocket.CLOSING: return GameWebSocketState.CLOSING; case WebSocket.CLOSED: return GameWebSocketState.CLOSED; } } return GameWebSocketState.CLOSED; } }); module.exports = { GameWebSocketState: GameWebSocketState, GameWebSocketDelegate: GameWebSocketDelegate, GameWebSocketInterface: GameWebSocketInterface, GameWebSocket: GameWebSocket };

  GameNetwork.js

/**
 * Created by skyxu on 2018/10/9.
 */

"use strict";

let GameWebSocket = require("./GameWebSocket");
let GameProtocols = require("./GameProtocols");

/**
 * 伺服器回覆訊息狀態,判斷回覆訊息的各種問題
 */
var response_state = {
    ERROR_OK : '0'
};

/**
 * 請求回撥物件,收到伺服器回撥後的回撥方法
 */
var NetworkCallback = cc.Class({

    properties: {

        /**
         * @type {BaseRequest} request
         */
        request: null,

        /**
         * 請求回撥對方法
         */
        callback: null
    },

    /**
     * @param {BaseRequest} request
     * @param {function(BaseResponse): boolean} callback
     */
    init: function (request, callback) {
        this.request = request;
        this.callback = callback;
    }
});


let GameNetwork = cc.Class({
    extends: GameWebSocket.GameWebSocketDelegate,

    ctor: function() {
        this._socket = null;

        this._delegate = null;

        /**
         * 每次傳送請求,都需要有一個唯一的編號
         * @type {number}
         * @private
         */
        this._requestSequenceId = 0;

        /**
         * 接受伺服器主動下發的response回撥
         * key 表示BaseResponse.act
         * @type {Object.<string, function(object.<string, *>)>}
         */
        this.pushResponseCallback = {};

        /**
         * 根據seq儲存Request和其callback,以便在收到伺服器的響應後回撥
         * @type {Object.<int, NetworkCallback>}
         * @private
         */
        this._networkCallbacks = {};
    },

    setDelegate: function (delegate) {
        this._delegate = delegate;
    },

    /**
     * 註冊伺服器主動推送的response 回撥
     */
    registerPushResponseCallback : function(act, callback){
        this.pushResponseCallback[act] = callback;
    },

    /**
     * 判斷socket已連線成功,可以通訊
     * @returns {boolean}
     */
    isSocketOpened: function(){
        return (this._socket && this._socket.getState() == GameWebSocket.GameWebSocketState.OPEN);
    },

    isSocketClosed: function () {
        return this._socket == null;
    },

    /**
     * 啟動連線
     */
    connect: function (url) {
        cc.log("webSocketUrls=" + url);
        this._requestSequenceId = 0;
        this._socket = new GameWebSocket.GameWebSocket();
        this._socket.init(url, this);
        this._socket.connect();
    },

    closeConnect: function () {
        if(this._socket){
            this._socket.close();
        }
    },

    onSocketOpen: function () {
        cc.log('Socket:onOpen');
        if(this._delegate && this._delegate.onNetworkOpen){
            this._delegate.onNetworkOpen();
        }
    },

    onSocketError: function () {
        cc.log('Socket:onError');
    },

    onSocketClosed: function (reason) {
        cc.log('Socket:onClose', reason);
        if (this._socket) {
            this._socket.close();
        }
        this._socket = null;

        if(this._delegate && this._delegate.onNetworkClose){
            this._delegate.onNetworkClose();
        }
    },

    onSocketMessage: function (msg) {
        this._onResponse(msg);
    },

    _onResponse: function(responseData){
        cc.log('response->resp:', responseData);
        var responseJson = JSON.parse(responseData);
        var responseClass = GameProtocols.response_classes[responseJson.act];
        /**
         * @type {object.<BaseResponse>}
         */
        var response = new responseClass();
        response.loadData(responseJson.data);
        response.act = responseJson.act;
        response.seq = responseJson.seq;
        response.err = responseJson.err;
        response.ts = responseJson.ts;

        // 如果指定了回撥函式,先回調
        var ignoreError = false;
        if(response.seq != -1){
            // 處理伺服器推送訊息
            var pushCallback = this.pushResponseCallback[response.act];
            if(pushCallback){
                pushCallback(response);
            }

            // request回撥
            var callbackObj = this._networkCallbacks[response.seq];
            if(callbackObj){
                ignoreError = callbackObj.callback(response);
                // try {
                //     ignoreError = callbackObj.callback(response);
                // } catch (err) {
                //     cc.log(err + " error in response callback of " + response.act);
                // } finally {
                //     delete this._networkCallbacks[response.seq];
                // }
            }
        }

        //有錯,且不忽略,則統一處理錯誤
        if(response.err && response.err != response_state.ERROR_OK && !ignoreError){
            if (response.is_async) {  // 非同步請求,如果出錯了,應該需要重新登入
                // todo 重新登入?或者重新同步資料?
            } else {  // 同步請求,如果出錯了,需要顯示錯誤資訊
                // todo 顯示錯誤
                var msg = responseJson.msg;
                cc.log('server err ' + msg);
            }
        }
    },

    /**
     * 向伺服器傳送請求。
     *
     * 如果提供了callback,在收到response後會被回撥。如果response是一個錯誤(status!=ERR_OK),則需要決定由誰來負責處理錯誤。
     * 如果callback中已經對錯誤進行了處理,應該返回true,這樣會忽略該錯誤。否則應該返回false,則負責處理該錯誤。
     *
     * 特別注意:如果這是一個非同步(is_async)請求,且出錯,一般來講應該重新登入/同步。但是如果callback返回了true,不會進行
     * 任何處理,也就是不會重新登入/同步。請小心確定返回值。
     *
     * @param {object.<BaseRequest>}
     * @param {function(BaseResponse): boolean=} opt_callback 回撥函式。出錯的情況下,如果返回true,則不會再次處理錯誤。
     */
    sendRequest: function (request, opt_callback) {
        // 每個請求的seq應該唯一,且遞增
        request.seq = ++this._requestSequenceId;

        //生成NetworkCallback物件,繫結請求seq和回撥方法
        if(opt_callback){
            this._networkCallbacks[request.seq] = new NetworkCallback();
            this._networkCallbacks[request.seq].init(request, opt_callback);
        }
        this._sendSocketRequest(false, request);
    },

    /**
     * sendRequest的不傳送data欄位
     */
    sendRequestNoData: function (request, opt_callback) {
        // 每個請求的seq應該唯一,且遞增
        request.seq = ++this._requestSequenceId;

        //生成NetworkCallback物件,繫結請求seq和回撥方法
        if(opt_callback){
            this._networkCallbacks[request.seq] = new NetworkCallback();
            this._networkCallbacks[request.seq].init(request, opt_callback);
        }
        this._sendSocketRequest(true, request);
    },

    /**
     * @param {Boolean} isNoData
     * @param {object.<BaseRequest>} req
     */
    _sendSocketRequest: function (isNoData, req) {
        cc.assert(this._socket);

        if (this.isSocketOpened()){
            //通過json的方法生成請求字串
            var msg = null;
            if(isNoData){
                msg = JSON.stringify({seq:req.seq, act:req.act});
            }else{
                msg = JSON.stringify({seq:req.seq, act:req.act, data:req});
            }
            cc.log("WebSocketDelegate::send->" + msg);
            this._socket.send(msg);
        } else{
            // todo
        }
    }
});

module.exports = GameNetwork;

  GameProtocols.js

/**
 * Created by skyxu on 2018/10/9.
 */

"use strict";

/**
 * 訊息基類物件,請求訊息BaseRequest, 回撥訊息BaseResponse都繼承BaseProtocol
 */
let BaseProtocol = cc.Class({
    ctor: function () {
        /**
         * 請求動作型別
         */
        this.act = '';

        /**
         * 每個請求的sequence_id應該唯一
         */
        this.seq = 0;

        /**
         * 錯誤程式碼,0為正常
         */
        this.err = 0;

        /**
         * 是否需要等待伺服器回撥
         */
        this.is_async = false;
    }
});

/**
 * 請求訊息基類,客戶端的請求都繼承這個類
 */
let BaseRequest = cc.Class({
    extends: BaseProtocol
});

/**
 * 伺服器返回的訊息對應的物件,包含返回資料,一般和BaseRequest成對使用
 * @class BaseResponse
 * @extends BaseProtocol
 */
let BaseResponse = cc.Class({
    extends: BaseProtocol,

    /**
     * 讀取返回資料,設定BaseResponse物件
     */
    loadData: function (data) {
        var key;
        for (key in data) {
            if(!this.hasOwnProperty(key)){
                continue;
            }

            if(data[key] !== undefined && data[key] !== null){
                this[key] = data[key];
            }
        }
    }
});

let HeartRequest = cc.Class({
    extends: BaseRequest,
    ctor(){
        this.act = 'heart';
        this.t = -1;    // 傳送時間
    }
});

let HeartResponse = cc.Class({
    extends: BaseResponse,

    ctor(){
        this.act = 'heart';
        this.t = -1;
    }
});

let ChatRequest = cc.Class({
    extends: BaseRequest,
    ctor(){
        this.act = 'chat';
        this.msg = '';
        this.uid = '';
    }
});

let ChatResponse = cc.Class({
    extends: BaseResponse,
    ctor(){
        this.act = 'chat';
        this.msg = '';
        this.uid = '';
    }
});

let LoginRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'login';

        /**
         * facebook使用者的accessToken,或遊客的UUID
         */
        this.token = '';

        /**
         * token來源,預設0:遊客,1:facebook
         */
        this.origin = 0;

        /**
         * 平臺: 必須為以下幾種之一:android/ios/winphone/pc
         */
        this.os = '';

        /**
         * 平臺系統版本
         */
        this.osVersion = '';

        /**
         * 裝置產品型號, 示例 iPhone8,2, SM-G 9280
         */
        this.deviceModel = '';

        /**
         * 渠道ID
         */
        this.channelId = 0;

        /**
         * Ios裝置廣告標示符
         */
        this.idfa = '';

        /**
         * 安卓裝置id
         */
        this.androidId = '';

        /**
         * Google廣告平臺賬號,安裝了google play的裝置可取到
         */
        this.googleAid = '';

        /**
         * 應用版本號
         */
        this.appVersion = '';

        /**
         * 取package name或者bundle id
         */
        this.packName = '';


        /**
         * 裝置語言
         * @type {string}
         */
        this.language = '';

        this.locale = "";

    }
});

let LoginResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'login';

        /**
         * 遊客第一次登入時返回的token,需要客戶端儲存
         */
        this.token = '';

        /**
         * 離體力下次恢復點的剩餘時間秒數
         * @type {number}
         */
        this.spStepLeftTime = 0;

        /**
         * 體力恢復週期
         * @type {Number}
         */
        this.spInterval = 0;

        /**
         * 農場每天產出量,產出未解鎖時為-1
         * @type {number}
         */
        this.farmDailyOut = -1;

        /**
         * 農場已產出量
         * @type {number}
         */
        this.farmCoins = 0;

        /**
         * 農場產出間隔
         * @type {number}
         */
        this.farmInterval = null;

        /**
         * 用json object表示的一個player物件,欄位說明參見player json物件
         */
        this.me = {};

        /**
         * 建築資料陣列
         * @type {Array}
         */
        this.buildings = [];

        /**
         * 農民資料陣列
         * @type {Array}
         */
        this.farms = [];

        /**
         * 富豪資料
         */
        this.cashking = {};

        /**
         * 行星配置
         */
        this.planetConf = {};

        /**
         * 農民配置
         */
        this.farmConfList = [];

        /**
         * 其他配置
         */
        this.settingConf = {};

        /**
         * 好友資料
         */
        this.friends = [];

        /**
         * 好友通緝的目標列表
         */
        this.helpWantList = [];

        /**
         * 郵件訊息列表
         */
        this.newsList = [];

        /**
         * 復仇列表
         */
        this.revengeList = [];

        /**
         * 商品資訊
         * @type {Array}
         */
        this.rechargeConfs = [];

        /**
         * 總島數
         * @type {Number}
         */
        this.planetConfListSize = 0;

        /**
         * 他人行星資訊物件,僅在轉到fire斷線重新登入時有效
         * @type {Object}
         */
        this.fireTarget = null;

        /**
         * 他人行星資訊物件列表,僅在轉到steal斷線重新登入時有效
         * @type {Array}
         */
        this.stealTarget = null;
    }
});

let LogoutRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'logout';
    }
});

let LogoutResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'logout';
    }
});

/**
 * 繫結fb賬號
 * @extends BaseRequest
 */
let BindFacebookRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'bindFb';

        /**
         * facebook使用者的accessToken,或遊客的UUID
         */
        this.token = '';
    }
});
/**
 * 繫結fb賬號
 * @extends BaseResponse
 */
let BindFacebookResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'bindFb';

        /**
         * fb資料
         */
        this.me = 0;

        /**
         * fb好友
         */
        this.friends = 0;
    }
});

let SpinRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'spin';

        /**
         * 倍數
         * @type {Number}
         */
        this.x = 1;
    }
});

let SpinResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'spin';

        /**
         * 搖中的轉盤ID
         */
        this.hit = 0;

        /**
         * 轉到護盾,但護盾已滿時,存在
         * @type {number}
         */
        this.shieldfull = 0;

        /**
         * 玩家資料物件
         */
        this.me = {};

        /**
         * 他人行星資訊物件,僅在轉到fire時有效
         * @type {*}
         */
        this.fireTarget = {};

        /**
         * 偷取物件資料
         */
        this.stealTarget = [];

        /**
         * 離體力下次恢復點的剩餘時間秒數
         * @type {number}
         */
        this.spStepLeftTime = 0;

        /**
         * 體力恢復週期
         * @type {Number}
         */
        this.spInterval = 0;

        /**
         * 倍數
         * @type {Number}
         */
        this.x = 1;
    }
});

/**
 * 獲取排名
 * @extends BaseRequest
 */
let RankRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'rankboard';

        /**
         * 請求動作型別{ 0全部,1本地,2好友 }
         * @type {int}
         */
        this.type = 0;
    }
});
/**
 * 獲取排名
 * @extends BaseResponse
 */
let RankResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'rankboard';

        /**
         *  我的排名
         */
        this.myRank = 0;

        /**
         * 排名玩家資料
         */
        this.men = [];
    }
});


//push------------------------------------------------------------------------------

/**
 * 推送訊息 被攻擊
 * @extends BaseResponse
 */
var PushAttackedResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'attacked';

        /**
         * 玩家更新資料
         */
        this.me = null;

        /**
         * 建築資料
         */
        this.building = null;

        /**
         * 敵人
         */
        this.hatredman = null;

        /**
         * 訊息
         */
        this.news = null;
    }
});


/**
 * 推送訊息 推送訊息好友已贈送體力
 * @extends BaseResponse
 */
var PushSendSpResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'sendSpNotify';

        /**
         * 好友物件
         */
        this.friend = null;
    }
});

/**
 * 推送訊息 推送訊息好友已領取贈送的體力
 * @extends BaseResponse
 */
var PushTakeSpResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'takeSpNotify';

        /**
         * 好友物件
         */
        this.friend = null;
    }
});

/**
 * 推送訊息 同步好友資訊
 * @extends BaseResponse
 */
var PushSyncFriendInfo = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'friendInfoSync';

        /**
         * 好友
         */
        this.friend = null;
    }
});

/**
 * 推送訊息 新增好友
 * @extends BaseResponse
 */
var PushAddNewFriend = cc.Class({
    extends: BaseResponse,

    ctor: function () {

        this.act = 'newFriend';

        /**
         * 好友
         */
        this.friend = null;

        /**
         * 訊息
         */
        this.news = null;
    }
});

/**
 * debug回撥
 * @extends BaseRequest
 */
let DebugChangeMeRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {

        this.act = "cmdTest";                    //請求動作型別
        this.cmd = "";
        //  "player coins add 100", cmd格式:player field value 或者 player field add value
        //  Building field [add] value where playerId value type value
    }

});
/**
 * debug回撥
 * @extends BaseResponse
 */
let DebugChangeMeResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = "cmdTest";

        /**
         * 玩家資料
         * @type {Object}
         */
        this.me = {};

        /**
         * 體力恢復週期
         * @type {Number}
         */
        this.spInterval = null;

        /**
         * 體力恢復剩餘時間
         * @type {Number}
         */
        this.spStepLeftTime = null;

        /**
         * 存錢罐速度
         * @type {Number}
         */
        this.farmDailyOut = null;

        /**
         * 存錢罐可回收金幣
         * @type {Number}
         */
        this.farmCoins = null;

        /**
         * 存錢罐回收週期
         * @type {Number}
         */
        this.farmInterval = null;

        /**
         * 島嶼建築資料
         * @type {Array}
         */
        this.buildings = null;
    }
});

let response_classes = {
    login: LoginResponse,
    logout: LogoutResponse,
    spin: SpinResponse,
    bindFb: BindFacebookResponse,
    rankboard: RankResponse,
    heart: HeartResponse,
    chat: ChatResponse,

    //push
    attacked: PushAttackedResponse,
    sendSpNotify: PushSendSpResponse,
    takeSpNotify: PushTakeSpResponse,
    newFriend: PushAddNewFriend,
    friendInfoSync: PushSyncFriendInfo,

    // debug
    cmdTest: DebugChangeMeResponse,
};

module.exports = {
    LoginRequest: LoginRequest,
    LoginResponse: LoginResponse,
    LogoutRequest: LogoutRequest,
    LogoutResponse: LogoutResponse,
    SpinRequest: SpinRequest,
    SpinResponse: SpinResponse,
    BindFacebookRequest: BindFacebookRequest,
    BindFacebookResponse: BindFacebookResponse,
    RankRequest: RankRequest,
    RankResponse: RankResponse,
    HeartRequest: HeartRequest,
    HeartResponse: HeartResponse,
    ChatRequest: ChatRequest,
    ChatResponse: ChatResponse,

    // debug
    DebugChangeMeRequest: DebugChangeMeRequest,
    DebugChangeMeResponse: DebugChangeMeResponse,

    //push訊息
    PushAttackedResponse: PushAttackedResponse,
    PushSendSpResponse: PushSendSpResponse,
    PushTakeSpResponse: PushTakeSpResponse,
    PushAddNewFriend: PushAddNewFriend,
    PushSyncFriendInfo: PushSyncFriendInfo,

    response_classes: response_classes
};

  NetProxy.js

/** * Created by skyxu on 2018/10/9. */"use strict";let GameNetwork = require("./GameNetwork");let GameProtocols = require("./GameProtocols");let GAME_SERVER_URL = 'ws://127.0.0.1:3000';// GAME_SERVER_URL = 'wss://echo.websocket.org';let NetProxy = cc.Class({    ctor: function () {        this.network = null;        this._cachePushCallback = [];    },    init: function () {        this.network = new GameNetwork();        this.network.setDelegate(this);        this.initPushCallback();    },    connect: function () {        this.network.connect(GAME_SERVER_URL);    },    closeConnect: function () {        this.network.closeConnect();    },    isNetworkOpened: function () {        return this.network.isSocketOpened();    },    isNetworkClosed: function () {        return this.network.isSocketClosed();    },    onNetworkOpen: function () {        Global.eventMgr.emit(Global.config.EVENT_NETWORK_OPENED);    },    onNetworkClose: function () {        Global.eventMgr.emit(Global.config.EVENT_NETWORK_CLOSED);    },    /**     * 註冊push回撥介面     */    initPushCallback: function () {        let self = this;        let pushCallback = function (resp) {            self.pushCallback(resp);        };        this.network.registerPushResponseCallback('chat', pushCallback);        // let pushCallback = function(response){        //     if(Util.DNN(farm.game) && farm.game.loginSuccess){        //         this.dealCachePush();        //         this.pushCallback(response);        //     }else{        //         this._cachePushCallback.push(response);        //     }        // }.bind(this);        // this.network.registerPushResponseCallback('attacked', pushCallback);        // this.network.registerPushResponseCallback('acceptWantHelp', pushCallback);        // this.network.registerPushResponseCallback('sendSpNotify', pushCallback);        // this.network.registerPushResponseCallback('takeSpNotify', pushCallback);        // this.network