6、Khala的登录生命周期管理

  khala能够对设备进行生命周期管理,并提供了与生命周期相关的接口,用户只需在具体的设备类型实现类中重写这些生命周期接口,即可享受khala对于生命周期管理的同时定制与业务相关的操作。具体接口解释如下:

onLoginCheckMsg():

  进行登录检查,在此可以通过查询DB等方式检查登录设备账号是否合法,可以为连接设备设置设备ID(此ID必须唯一,将被视为设备key,若出现重复将执行onLoginFailureMsg,若未设置将以临时ID值作为ID key),若账号检查失败,设置失败回复消息并直接返回false即可。若检查成功,并且设置的ID未重复,将完成登录操作并执行onLoginSuccessMsg。

onLoginSuccessMsg():

  登录成功,在此可以执行登录成功后的相关操作。此时设备进入登录设备的生命周期。

onLoginFailureMsg():

  登录异常,设置ID与已登录的设备ID冲突,一般表明该账号已登录。

onLogoutMsg():

  注销操作,表明该账号退出登录。此操作结束后,将执行releaseConnNode释放该设备的相关资源,并结束该设备的登录生命周期,并最终断开连接。

releaseConnNode():

  释放设备资源。将在退出设备生命周期时被执行,一般在设备执行注销操作后执行,但在设备异常退出的时候,也会执行该操作。

  我们通过建立一个MyUsrType的设备类型为来体验khala的设备生命周期。MyUsrType通过继承于NodeType享受登录设备管理,并对相关的生命周期接口进行重写定制。

我们在mysql中建立名为UsrInfo的表,用来记录设备账号信息。在此我们新建了两个账号,分别为moss1和moss2,且我们通过DB维护了每个账号的不同id。

image

  我们在onLoginCheckMsg中对登录账号信息查询DB进行检查。具体的DB操作我们可以通过封装mysql++实现,具体相关可百度mysql++文档。若该账号不存在,我们回复登录失败的消息,并返回false,即结束了此次登录请求操作。若该账号存在,我们将DB中保存的ID作为设备ID。并返回true。

virtual bool onLoginCheckMsg(khala::InfoNodePtr& infoNodePtr,
            Json::Value& msg, khala::Timestamp time) {
    //获取账号名
    std::string name = msg[KEY_LOGIN_NAME].asString();
    //获取密码
    std::string passwd = msg[KEY_PASSWD].asString();
    //查询DB
    UsrInfoResult res = UsrInfoDao::getInstance().queryUsrInfo(name,passwd);
    if (!res.isSuccess()) {
        //该账号不存在
        infoNodePtr->send("login failure,err account!");
        return false;
    }
    //获取DB查询信息
    UsrInfoDo usrInfoDo = res.getUsrInfoDo();
    //将设备ID设置为DB中保存的ID
    infoNodePtr->setId(usrInfoDo.id);
    return true;
}

  之后系统将会以该ID做为key对已登录设备进行检查,若该ID在已登录设备中存在,则表明该账号已经登录,将执行onLoginFailureMsg操作。此处我们实现的onLoginFailureMsg操作很简单,仅仅只是告诉客户端该ID所对应的设备账号已经登录,此次登录失败。

virtual bool onLoginFailureMsg(khala::InfoNodePtr& infoNodePtr,
            Json::Value& msg, khala::Timestamp time) {
    infoNodePtr->send("login failure,logined id!");
    return true;
}

  若该ID未登录,则会执行相应的登录操作,将该连接信息保存到登录设备池等。并最后执行onLoginSuccessMsg,表明该设备账号登录成功,正式进入登录生命周期中。我们可以在此实现登录成功后的相关操作。我们在此的实现也很简单,告诉客户端此次登录成功,且设备的ID为多少。

virtual bool onLoginSuccessMsg(khala::InfoNodePtr& infoNodePtr,
        Json::Value& msg, khala::Timestamp time) {
    std::stringstream ss;
    ss << "login success! your id is:" << infoNodePtr->getId();
    infoNodePtr->send(ss.str());
    return true;
}

  至于注销操作,依旧只需实现具体的和业务相关的消息返回就行,Khala系统收到注销操作后,将会自行处理之前维护的设备信息,将其释放并调用releaseConnNode释放设备申请的相关资源,最后结束此次登录的生命周期并断开连接。

virtual bool onLogoutMsg(khala::InfoNodePtr& infoNodePtr, Json::Value& msg,
        khala::Timestamp time) {
    std::stringstream ss;
    ss << "logout success! your id is:" << infoNodePtr->getId();
    infoNodePtr->send(ss.str());
    return true;
}

  因为此次设备并未主动申请相关资源,因此releaseConnNode操作无需进行任何操作,但为了展示releaseConnNode在设备登录生命周期的时机,我们通过系统日志进行相关输出。

virtual void releaseConnNode(khala::InfoNodePtr& infoNodePtr,
            khala::Timestamp time) {
    LOG_INFO << "this is node id:" << infoNodePtr->getId()<< " release function!";
}

  最后,我们还要为我们的MyUsrType设置类型名,同时在main中进行注册操作,此处不谈。

MyUsrType的完整代码见最后。

  我们通过客户端进行测试(./example/testClient/HelloKhalaClient3.py)。

  我们选择登录操作,并且选择登录类型为usrType,然后输入moss1的账号密码,此时显示我们登录成功,且id为1,正是DB中moss1对应的ID。我们再查询isLogin命令,显示我们已经登录。查询devType,正是我们新创建的MyUsrType类型。

image

  如果我们输入一个错误的账号密码,结果返回错误的账号,且查询isLogin显示未登录。

image

  此时我们的moss1账号已经登录,如果我们再开启一个客户端,通过moss1账号进行登录操作。此时返回onLoginFailureMsg中的处理,即该账号已经在别处登录,此次登录失败。

image

  我们再在已经登录的moss1账号上进行注销操作。我们收到正确的注销操作返回,连接被断开。

image

  此时我们查询khala服务端日志,显示releaseConnNode被成功执行。

image

  我们再次开启客户端,并用moss1账号登录,再通过ctr+c强制客户端退出,此时我们再检查日志,显示系统检测到客户端异常退出,同时releaseConnNode依旧得到了执行。因此如果我们在登录连接中申请了相关资源,不管客户端最后是正确被注销退出还是异常情况下退出,只要我们在releaseConnNode中执行了正确的申请资源释放操作,都不会导致服务端因为资源泄露而出错。

image

  完整的MyUsrType类代码:

#include <khala/NodeType.h>
#include <sstream>
#include"DAO/UsrInfoDao.h"
class MyUsrType: public khala::NodeType {
public:
    MyUsrType();
    virtual ~MyUsrType();
    virtual bool onLoginCheckMsg(khala::InfoNodePtr& infoNodePtr,
            Json::Value& msg, khala::Timestamp time) {
        std::string name = msg[KEY_LOGIN_NAME].asString();
        std::string passwd = msg[KEY_PASSWD].asString();
        UsrInfoResult res = UsrInfoDao::getInstance().queryUsrInfo(name,
                passwd);
        if (!res.isSuccess()) {
            infoNodePtr->send("login failure,err account!");
            return false;
        }
        UsrInfoDo usrInfoDo = res.getUsrInfoDo();
        infoNodePtr->setId(usrInfoDo.id);
        return true;
    }
    virtual bool onLoginSuccessMsg(khala::InfoNodePtr& infoNodePtr,
            Json::Value& msg, khala::Timestamp time) {
        std::stringstream ss;
        ss << "login success! your id is:" << infoNodePtr->getId();
        infoNodePtr->send(ss.str());
        return true;
    }
    virtual bool onLoginFailureMsg(khala::InfoNodePtr& infoNodePtr,
            Json::Value& msg, khala::Timestamp time) {
        infoNodePtr->send("login failure,logined id!");
        return true;
    }
    virtual bool onLogoutMsg(khala::InfoNodePtr& infoNodePtr, Json::Value& msg,
            khala::Timestamp time) {
        std::stringstream ss;
        ss << "logout success! your id is:" << infoNodePtr->getId();
        infoNodePtr->send(ss.str());
        return true;
    }
    virtual void releaseConnNode(khala::InfoNodePtr& infoNodePtr,
            khala::Timestamp time) {
        LOG_INFO << "this is node id:" << infoNodePtr->getId()
                << " release function!";
    }
    virtual const std::string& getObjectTypeName() {
        static std::string typeStr(MY_USR_TYPE);
        return typeStr;
    }
};
原文地址:https://www.cnblogs.com/moyangvip/p/5058397.html