pomelo获取玩家连接事件,完整实现

当有玩家连接过来,服务器需要做一些处理,这个很有必要。

如果你在app.configure(...()=>{

//增加connector的事件,结果是无效的。因为app还没有start。connector还没有初始化。

})

事实上是app.configure的回调是立马执行的。

下面是configure的代码实现:

Application.configure = function (env, type, fn) {
  var args = [].slice.call(arguments);
  fn = args.pop();
  env = type = Constants.RESERVED.ALL;

  if(args.length > 0) {
    env = args[0];
  }
  if(args.length > 1) {
    type = args[1];
  }

  if (env === Constants.RESERVED.ALL || contains(this.settings.env, env)) {
    if (type === Constants.RESERVED.ALL || contains(this.settings.serverType, type)) {
      fn.call(this);
    }
  }
  return this;
};

//所以在configure回调处理是不行的。在这里主要处理服务器启动前,需要处理的配置。


后来发现,app会调用lifecycle.js,

会加载app/servers/xxxx/lifecycle.js,//xxxx是servers.json配置的服务器名称

并且对应了服务器启动的四个周期,分别是beforeStartup, afterStartup,beforeShutdown,afterStartall,因为我们需要在服务启动后,才能注册connection事件,所以我们应该在afterStartup中,添加connection事件处理。具体看下面的代码。

如app/servers/connector/lifecycle.js

let {SessionCheckOnConnect} = require("../../module/sessioncheck");
module.exports.beforeStartup = function(app, cb) {
// do some operations before application start up
//服务器启动前
//log.debug("beforeStartup:" + app.getServerId());
cb();
};
module. exports. afterStartup = function( app, cb) {
let connector = app.components[ '__connector__'];
connector.connector. on( 'connection',( socket) =>{
SessionCheckOnConnect(connector.session, socket); //这个是对连接过来处理的函数,主要用于绑定相关函数
});
//服务器启动后
//log.debug("afterStartup:" + app.getServerId());
cb();
};
module. exports. beforeShutdown = function( app, cb) {
//服务器关机前
//log.debug("beforeShutdown:" + app.getServerId());
cb();
};
module. exports. afterStartAll = function( app) {
//所有服务器启动后
//log.debug("afterStartAll:" + app.getServerId());
};

//下面是sessionCheck的完整代码

let {utils, getLogger} = require("../../jscommon");

let log = getLogger(__filename);


const MIN_INTERVAL    = 1000;
const DEFAULT_TIMEOUT = 30000;

/**
 * session检查类, 用于检查没有登录的连接,如果超时指定的时间没有登录成功,则踢掉
 */
class SessionCheck {
    constructor() {
        //super();

        this.m_app      = null;
        this.m_timeid   = null;
        this.m_open     = false;
        this.m_interval = MIN_INTERVAL;
        this.m_timeout  = DEFAULT_TIMEOUT;
        this.m_sidmap   = {};

    }
    /**
     * 初始化会话检查
     * @param {Application} paramApp pomelo的application对象
     * @param {boolean} paramOpen 是否打开会话检查
     * @param {number} paramInterval 每次检查的时间间隔,最小1000ms
     * @param {number} paramTimeout 会话的超时时间
     * @return {void}
     */
    init(paramApp, paramOpen, paramInterval, paramTimeout) {
        this.m_app = paramApp;
        if(!Number.isInteger(paramInterval) || paramInterval < MIN_INTERVAL) {
            this.m_interval = MIN_INTERVAL;
        }
        else {
            this.m_interval = paramInterval;
        }

        if(!Number.isInteger(paramTimeout) || paramTimeout < 10){
            this.m_timeout = DEFAULT_TIMEOUT;
        }
        else {
            this.m_timeout = paramTimeout;
        }

        if(utils.isNotNull(this.m_timeid)) {
            clearInterval(this.m_timeid);
            this.m_timeid = null;
        }

        if(paramOpen) {
            this.m_open = true;
        }
        else {
            this.m_open = false;
        }

        if(this.isOpen) {
            log.info("open SessionCheck: interval=" + this.m_interval);
            this.m_timeid = setInterval(()=>{ this.__onTick(); }, this.m_interval);
        }
    }
    /**
     * 清空被检查的session id
     * @return {void}
     */
    clear() {
        this.m_sidmap = {};
    }

    /**
     * 当有连接过来时
     * @param {Number} paramSessionId 连接过来的id
     * @return {void}
     */
    doConnect(paramSessionId) {
        let v = {sid:paramSessionId, t:Date.now()};
        this.m_sidmap[paramSessionId] = v;
    }
    /**
     * 当前连接关闭时
     * @param {Number} paramSessionId 被关闭的连接
     * @return {void}
     */
    doClose(paramSessionId, /*paramReason*/) {
        let v = this.m_sidmap[paramSessionId];
        if(utils.isNotNull(v)) {
            delete this.m_sidmap[paramSessionId];
        }
        //this.emit("close", paramSessionId, paramReason);
    }
    /**
     * 当有连接绑定时
     * @param {Number} paramSessionId 被绑定的连接
     * @return {void}
     */
    doBind(paramSessionId, /*paramUID*/) {
        //this.emit("bind", paramSessionId, paramUID);
        let v = this.m_sidmap[paramSessionId];
        if(utils.isNotNull(v)) {
            delete this.m_sidmap[paramSessionId];
        }
    }

    /**
     * 每次检查tick到达
     * @private 私有函数
     */
    __onTick() {
        let nNow = Date.now();

        let app = this.app;

        if(utils.isNull(app)||utils.isNull(app.sessionService)) {
            log.error('app is null');
            return;
        }

        let nTimeout = nNow - this.m_timeout;
        let sidmap = this.m_sidmap;
        for(let sid in sidmap) {
            let v = sidmap[sid];
            if(utils.isNull(v)) {
                delete sidmap[sid];
                continue;
            }
            if(v.t < nTimeout) {
                log.debug('session:' + v.sid + ' is timeout');
                delete sidmap[sid];
                app.sessionService.kickBySessionId(sid);
            }
            log.debug(`sid=${sid} t = ${v.t  - nTimeout}s`);
        }
    }

    get app() {
        return this.m_app;
    }

    get isOpen() {
        return this.m_open;
    }
}

/**
 * 会话检查对象
 */
let sessionCheck = new SessionCheck();


/**
 * 会话检查的连接函数
 * @param {Sessions} paramSessionService pomelo的会话管理service
 * @param {Socket} paramSocket 连接过来的socket对象
 * @return {void}
 */
function SessionCheckOnConnect(paramSessionService, paramSocket){
    let sid = paramSocket.id;
    sessionCheck.doConnect(sid);
    let session = paramSessionService.get(sid);
    if(utils.isNotNull(session)) {
        session.on('closed', (paramSession, paramReason)=>{
            sessionCheck.doClose(paramSession.id, paramReason);
        });
        session.on('bind', (uid)=>{
            sessionCheck.doBind(sid, uid);
        });
    }
    else {
        log.debug("not found session by sid:", sid);
    }
}


exports.sessionCheck = sessionCheck;
exports.SessionCheckOnConnect = SessionCheckOnConnect;

//然后在app.js connector加入对它的初始化

app.configure('production|development', 'connector', async ()=> {
    log.info("connector configure...: ", app.servers);
    app.set('connectorConfig',
        {
            connector: pomelo.connectors.hybridconnector,
            heartbeat: 3,
            useDict: true,
            useProtobuf: true,
            handshake: function (msg, cb) {
                let user = msg.user;
                if (!user || !user.key || user.key !== app.game_config.static_config.common.key) {
                    cb(404, {});
                    return;
                }
                cb(null, {});
            }
        });
    //这里加入初始化sessionCheck
    let sessioncfg = static_config.common.session;
    let {sessionCheck} = require('./app/module/sessioncheck');
    sessionCheck.init(app, sessioncfg.open, sessioncfg.interval, sessioncfg.timeout);
});
在这个实现过中用,使用了connection,bind,closed等事件。早期的版本是用查询所有的session来判,现在这个版本,则只会对新来的connection做检查判断。这样就提升了效率。

你可能感兴趣的:(nodejs,pomelo,pomelo)