gyb-e改造说明

来源:互联网 发布:淘宝王小说 编辑:程序博客网 时间:2024/04/30 00:46

1.用户采用(机构ID,用户编号)识别

端点ID扩展为2个32位整数,通常只用低32位,只有对于用户,高32位机构ID表示用户编码域。

废除common.h中的以下宏:
/*#define ORGID_IN_USERSERIAL(u) (u/10000)#define ORGMINUSERSERIAL(u) (u*10000)#define ORGMAXUSERSERIAL(u) (u*10000 + 9999)#define GETORGID(t,id) (t==1 ? id : ORGID_IN_USERSERIAL(id))*/


1.1一般规则

。目标为用户的消息都要设置机构ID。采用的方法为:msg->SetDest(2,用户编号,机构ID);
。所有参数为用户编号的函数都要增加一个orgid参数.
。协议中涉及用户的都需要增加用户机构

1.2数据库修改

。tb_multitalk_member 增加orgid
ALTER TABLE tb_multitalk_member ADD COLUMN orgid INT COMMENT '机构ID' AFTER talk_id;

1.3协议修改

已明确修改的协议有

521-Request:请求行集增加列orgid.表示用户的机构ID,作为第一列。返回的确认消息的行集增加orgid列。
540-Request需要增加参数obj_h_id,表示对象ID的高字,可缺省。
515-Indication:增加参数orgid.表示登录用户的机构ID。    
538-Request:请求行集增加orgid列

后续修改注意这些协议的变化。

1.4todo

未实现的有:

。用户编号生成的逻辑需要修改,每个机构的内部用户编号从1开始,新建用户时取当前该机构最大编号+1作为新用户的内部编号.


2.rto_im实现

rto_im插件实现的主要代码如下:

int CImRto::CheckValid() {    parent::CheckValid();        router_->RegisterRouteHandler(dynamic_cast<IRouteHandler*>(this)); ///< 注册路由处理器    return 0;        }////////////////////////////////////////////////////////////////////////////////int CImRto::HandleInput(CWrappedMsg<> *pwm,int &action,int &break_flag) {    CMsg *msg = pwm->msg;    int dest_t;    unsigned long dest_id_hi,dest_id_lo;    msg->GetDest(dest_t,dest_id_lo,&dest_id_hi);    if (dest_t!=PT_ORG_USER) ///< 本插件只处理目标为用户的消息的路由        return 0;        ///< 处理逻辑:    ///< 如果用户在线,    ///<  如果是登录在本服务器,则直接在本机转发;否则,交给上级路由,    ///< 如果用户不在线,    ///< 根据消息是否可靠决定是否保存在用户待办事宜中.    IUSERINFO *user = mem_data_->GetUser(dest_id_hi,dest_id_lo);    if (user) {        ///< 对于需要用户就绪才能发送的消息,检查用户就绪状态        bool ready_flag = msg->GetMsgAttr() & EXTEND1_MASK;        if (ready_flag) {            if (!user->IsReady()) {                user->Release();                user = 0; ///< 如果用户未就绪按未登录处理            }        }    }    if (user) {        if (user->GetSvrID()==mem_data_->GetLocalServer()->GetServerID()) {            msg->Duplicate();            CWrappedMsg<> *resp = new CWrappedMsg<>;            resp->Attach(msg);            resp->AddChannelHandle(user->GetHandle());            network_->SendMsg(resp);            user->Release();            return 1;        }        else {            break_flag = 1; ///< 终止其它路由处理器处理,由指定的转发路由函数处理.            user->Release();            return 0; ///< 未路由.        }    }    else {        if(msg->IsTrusted()) {            if (msg->RecoverMsg()) {                return -1;            }            CMsg *app_msg = msg->PopAppMsg();            msg->Release();            if (SaveMsgForTODO(CSEMQTodoItem(app_msg),false)) {                action = 0;                pwm->Attach(app_msg);                return -2;            }            pwm->Attach(app_msg);            return 1; ///< 处理结束,不再由其它路由处理器处理        }    }    return 0;}

3.x_swich插件实现

x_switch负责平台服务器之间传输信息.提供以下功能:

.处理平台服务器的注册和注销

.检测和处理平台服务器断开

.路由消息

代码如下:

MSG_FUNC_MAP CXSwitch::func_[] = {{498,MT_REQUEST,(MSGFUNC)&OnServerLogout,true,"服务器注销","服务器注销"},{499,MT_REQUEST,(MSGFUNC)&OnServerLogin,true,"服务器注册","服务器注册"},};////////////////////////////////////////////////////////////////////////////////int CXSwitch::OnActivate() {parent::OnActivate();///< 注册连接事件处理器reactor_->register_handler(this,HTX_Reactor_Base::CONNECT_MASK|HTX_Reactor_Base::CLOSE_MASK);return 0;}////////////////////////////////////////////////////////////////////////////////int CXSwitch::OnServerLogin(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or){CMsg *req = in->msg;const char *serverid = req->GetParam("ServerID");const char *name = req->GetParam("Name");const char *desc = req->GetParam("Desc");if (ISEMPTY_STR(serverid) || ISEMPTY_STR(name) ||ISEMPTY_STR(desc)) {RespError(req,out,ERR_PROTO_ARG,true);return-1;}nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"服务器(ID:%s)正在注册...\r\n",serverid); CQQ_SERVERID ulServerID = atol(serverid);IINNERSERVERINFO *server = dynamic_cast<IINNERSERVERINFO*>(mem_data_->GetInnerServer(ulServerID));if (server) {///< 服务器已注册nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"GetServer() ServerID:%s已经存在.\n",serverid);CQQ_CHANNEL_ID handle = server->GetHandle();if (mem_data_->RemoveInnerServer(ulServerID)) {nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"RemoveInnerServer() ServerID:%s失败.\n",serverid);RespError(req,out,ERR_SERVER_REGISTERED,true);return -2;}network_->unbind_entity(handle);network_->CloseSocket(handle);}else {server = mem_data_->NewInnerServer();}CWrappedMsg<> *ans = new CWrappedMsg<>;ans->msg = new CMsg;ans->msg->SetMsgID(req->GetMsgID());ans->msg->SetCmdSerial(req->GetCmdSerial());ans->msg->SetMsgType(MT_CONFIRMATION);time_t svr_online_time;time(&svr_online_time);server->svr_id(ulServerID);server->handle(in->connid[0]);//server->svr_name(name);//server->svr_desc(desc);server->onlinetime(svr_online_time);server->rsp_id(atol(this->svr_info_->id().c_str()));server->set_status(Sock_Peer_Base::SPT_TRUSTED);if (network_->bind_entity(in->connid[0],&Handler_Bind_Context(dynamic_cast<Sock_Peer_Base*>(server),0))) {server->Release();delete ans;return -3; ///< 此时连接已经断开}int ret = mem_data_->AddInnerServer(server);if (ret) {server->Release();delete ans;RespError(req,out,ERR_UPDATE_MEMDB,true);return -4;}bool trusted = true;network_->set_handler_attr(in->connid[0],HA_TRUSTED,(char*)&trusted,sizeof(trusted));server->Release();out.push_back(ans);CInnerServerRegEvent *e = new CInnerServerRegEvent(ulServerID); event_controller_->pulse(CEventBase::INNER_SERVER_REGISTER,e);DEBUG_LOG(nlogger_,(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"OnSererLogin() Server ID:%s OK!\n",serverid));return 0;}////////////////////////////////////////////////////////////////////////////////int CXSwitch::OnServerLogout(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) {if (!(in->GetFlag()&CWrappedMsg<>::ML_FAKE)) { CMsg *tmsg = new CMsg;tmsg->SetMsgType(MT_CONFIRMATION);tmsg->SetMsgID(in->msg->GetMsgID());CWrappedMsg<> *twm = new CWrappedMsg<>;twm->msg = tmsg;twm->SetFlag(CWrappedMsg<>::ML_CLOSE);out.push_back(twm);return 0;}const char *serverid = in->msg->GetParam("ServerID");if (ISEMPTY_STR(serverid))return -1;CQQ_SERVERID ulServerID = atol(serverid);IINNERSERVERINFO *server = dynamic_cast<IINNERSERVERINFO*>(mem_data_->GetInnerServer(ulServerID));if (server==0)return -2;if( server->GetRSPID() == mem_data_->GetLocalServer()->GetServerID() ){if( server->GetHandle() == in->connid[0] ){mem_data_->RemoveInnerServer(ulServerID); }}server->Release();CInnerServerUnRegEvent *e = new CInnerServerUnRegEvent;e->serverid_ = ulServerID;int result = this->event_controller_->pulse(CEventBase::INNER_SERVER_OFFLINE,e);return 0;}////////////////////////////////////////////////////////////////////////////////int CXSwitch::handle_input(unsigned long fd, HTX_Reactor_Mask masks,HTX_Event_Arg *arg) {ACE_SOCKET handle = (ACE_SOCKET)fd;if (masks==HTX_Reactor_Base::CLOSE_MASK) { if (arg->entity_) {Sock_Peer_Base *client = arg->entity_;int client_type = client->type(); ///< 连接实体类型if(client_type!=CLIENT_TYPE_INNER_SERVER) return 0;Sock_Peer_Base::SockPeerStatus status = client->status();if (status&Sock_Peer_Base::SPT_BROKEN) return 0;CMsg *msg = new CMsg;string sc_key;ISERVERINFO *server = dynamic_cast<ISERVERINFO*>(client);msg->SetMsgType(MT_REQUEST);msg->SetMsgID(498);msg->AddParam("ServerID",(long)server->GetServerID());sc_key = LogMsg("%d,%d,%d,%d",0,30,15,server->GetServerID());CUMXT *tmsg = CUMXT::New(msg);tmsg->SetSeqControlKey(sc_key.c_str());CWrappedMsg<> *pwm = new CWrappedMsg<>;pwm->msg = tmsg;pwm->connid.push_back(handle);pwm->SetFlag(CWrappedMsg<>::ML_FAKE);time(&pwm->timestamp_);network_->FeedSelf(pwm);}}return 0;}///////////////////////////////////////////////////////////////////////int CXSwitch::HandleInput(CWrappedMsg<> *pwm,int &action,int &break_flag) {CMsg *msg = pwm->msg;int tt_d;unsigned long tid_d,h_tid_d; msg->GetDest(tt_d,tid_d,&h_tid_d);switch(tt_d) {case PT_ORG_USER: {IUSERINFO *user = mem_data_->GetUser(h_tid_d,tid_d);if (user==0) {return -1;}///< 不考虑本地服务器支持的情况,用户登录的服务器,平台服务器,内部服务器是同一个概念.///< tb_svr应该是存储级联的本地服务器的信息.tb_inner_svr则保存的是平台服务器信息.CQQ_SERVERID svr_id = user->GetSvrID(); CHANNEL_ID handle = 0;if (svr_id==mem_data_->GetLocalServer()->GetServerID()) { ///< 如果目标用户是登录在本服务器上handle = user->GetHandle();user->Release();}else { ///< 否则转发到该用户所登录的服务器上.user->Release();IINNERSERVERINFO *server = mem_data_->GetInnerServer(svr_id);if (server==0) return -1;handle = server->GetHandle();server->Release();}CWrappedMsg<> *twm = new CWrappedMsg<>;twm->msg = msg->Duplicate();twm->AddChannelHandle(handle);network_->SendMsg(twm);  }break;case PT_ORG: ///< 平台版才有需要转发不同机构的消息.企业版目前没有这种情况break;default:return 0;}return 1;}

4.linkto_switch实现

1.linkto_switch.h

////////////////////////////////////////////////////////////////////////////////class clinkto_switch: public clinkto_base{typedef clinkto_base parent;friend int sc_send_msg(CMsg *msg);static clinkto_switch* instance_;static MSG_FUNC_MAP func_[];protected:clinkto_switch(void);int OnConnectToSEP();int OnDisconnectSEP();public:~clinkto_switch(void);static clinkto_switch* instance() {if (instance_==0)instance_ = new clinkto_switch;return (clinkto_switch*)instance_;}protected:int ReadPrivateConfig();int Initialize();int Prepare();int CheckValid();int Activate();int OnActivate();int Deactivate();int Release();};

2.linkto_.cpp主要代码

////////////////////////////////////////////////////////////////////////////////int clinkto_switch::OnConnectToSEP() {char sz_func_name[] = "clinkto_switch::OnConnectToSEP";nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"clinkto_switch::OnConnectToSEP...\n");char *pServerID = const_cast<char*>(svr_info_->id().c_str());assert(pServerID!=0);OutputSyncCallBegin(sz_func_name,MT_REQUEST,499,"注册服务器");CMsg *msg = new CMsg;msg->SetMsgType(MT_REQUEST);msg->SetMsgID(499);msg->AddParam("ServerID", pServerID);msg->AddParam("Name", svr_info_->name().c_str());msg->AddParam("Desc", svr_info_->desc().c_str());msg->SetMsgAttr(SYNC_CALL_MASK);CUMXT *nmsg = CUMXT::New(msg);string sc_key;sc_key = LogMsg("%d,%d,%d,%s",0,30,15,pServerID);nmsg->SetSeqControlKey(sc_key.c_str());int result = 0;int ret = sc_->call(nmsg,result,0,(SC_CALLBACK)sc_send_msg,sync_call_timeout_);OutputSyncCallEnd(sz_func_name,ret,result);switch(result) {case 1:central_server_.connector_->close(); ///< 不再尝试连接break;case 2:central_server_.connector_->set_retry_delay(30); ///延迟尝试central_server_.connector_->close(false); ///< 继续尝试连接break;case -99:central_server_.connector_->close(); ///< 不再尝试连接nlogger_->sync_log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"验证或注册机器指纹失败,开始停止服务.\n");mgr_->StopService(1);break;default:if (result||ret)central_server_.connector_->close(false); }if (result||ret)return -3;event_controller_->pulse(CEventInfo::SERVER_REGISTER0,0); ///< 激发SERVER_REGISTER0事件central_server_.logon_ = true; nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"clinkto_switch::OnConnectToSEP ok.\n");return 0;}////////////////////////////////////////////////////////////////////////////////int clinkto_switch::OnDisconnectSEP() {nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"CAPPlugin::OnDisconnectSEP.\n");central_server_.logon_ = false;nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CAPPlugin::OnDisconnectSEP ok.\n");return 0;}

3.linkto_base

是linkto_xxx的基类.

////////////////////////////////////////////////////////////////////////////////class clinkto_base: public CQQBasePlugin,public IRouteHandler,public HTX_Event_Handler ,public IEventHandler {typedef CQQBasePlugin parent;friend class CConnectorEventTask;protected:INET_CTLconn_cfg_;st_sock_buf_sizest_socksize_;///< 通信缓冲区大小;unsigned intsync_call_timeout_;///< 同步调用超时时间CCentralServercentral_server_;///< 平台服务器对象CConnectorEventTaskconnector_task_;///< 连接器事件处理任务(只能有一个线程)int m_RegStat;protected:virtual int OnConnectToSEP() = 0;virtual int OnDisconnectSEP() = 0;int SendMsgToCenter_i(char *buffer,unsigned long len); int SendMsgToCenter_i(CMsg *msg);int OnConnectorEvent(CHANNEL_ID handle,int event,SERVERINFO *server);void OutputSyncCallBegin(const char *caption,MSGTYPE msg_type,MSGID msgid,const char *desc); ///< 输出同步调用开始信息void OutputSyncCallEnd(const char *caption,int ret,int result); ///< 输出同步调用结束信息int CanSend(short dest_type,unsigned long lo_dest_id,unsigned long hi_dest_id=0);bool IsIncomingMsg(CWrappedMsg<> *pwm); ///< 是否是来自平台的消息(外部进入本地的消息)int IsConnectedCentral();int SendMsgToCenter(CMsg *msg,bool logon=false);int TransferMsg(CMsg *Msg);int GetMinfo(string &sinfo);protected:int ReadPrivateConfig();int Activate();int Deactivate();int CheckValid();int handle_input(unsigned long fd, HTX_Reactor_Mask masks,HTX_Event_Arg *arg);int handle_event(EVENT_TYPE e,void *arg);int Check(CWrappedMsg<> *pwm,long &flag);int Check(PktHead *hd,long &flag);int HandleInput(CWrappedMsg<> *pwm,int &action,int &break_flag);int HandleSend(CMsg *msg,CWrappedMsg<> **wm);public:clinkto_base();};

5.路由框架介绍

1.IRouter接口

const char BBOX_ROUTER[] = "BCQ.BBOX_ROUTER";/////////////////////////////////////////////////////////////////////////////////////< 拦截器函数类型/// @return 0:未拦截 1:已拦截.已拦截的消息不再后续处理typedef int (*MsgInterceptFunc)(CMsg *msg);////< 是否拦截消息的检查函数typedef bool (*MsgInterceptCheckFunc)(CMsg *msg);class clinkto_base;///< 本地模式时检查是否已连接上级路由函数指针typedef int (clinkto_base::*CheckLinktoFuncPtr)(void); ///< 转移路由处理函数(如用于本机无法路由时交给上级路由模块)typedef int (clinkto_base::*TransferRouteFuncPtr)(CMsg *msg);/////////////////////////////////////////////////////////////////////////////////// @class IRouter/// @brief 路由接口class IRouter {public:enum {FLAG_STOP=0x00000001, ///< 此标志指示进程在处理路由时出现问题,需要重新启动服务器. FLAG_DONT_ROUTE=0x00000002,///< 指示消息到达目标,交给插件处理,不再路由};public:/// 对进入的消息进行路由处理virtual int HandleInput(CWrappedMsg<> *pwm,void **loc,int &reaction) = 0; /// 为待发送的msg消息选择发送路径virtual int HandleSend(CMsg *msg,CWrappedMsg<> **wm) = 0; ///< 消息处理完毕的后续处理,如自动返回确认,/// action=1:回复确认virtual int PostHandle(CMsg *msg,void *loc,int action) = 0; virtual int RegisterInterceptor(MsgInterceptCheckFunc,MsgInterceptFunc) = 0;    ///< 增加一个通道    virtual int AddChannel(unsigned long handle,int entity_type,__int64 entity_id,unsigned long prop) = 0;    ///< 删除一个通道    virtual int RemoveChannel(unsigned long handle) = 0;///< 登记一个路由模块virtual int RegisterRouteHandler(IRouteHandler *handler) = 0;///< 移除登记的路由模块virtual void RemoveRouteHandler(IRouteHandler *handler) = 0;///< 能否对指定的目标路由virtual int CanSend(short dest_type,unsigned long lo_dest_id,unsigned hi_dest_id=0) = 0;///< 检查消息头virtual int CheckMsgHead(PktHead *hd,long &flag) = 0;///< 设置上级路由virtual void SetLinkto(clinkto_base *linkto) = 0;///< 设置上级路由器连接检查函数virtual void SetCheckLinktoFunc(CheckLinktoFuncPtr fp) = 0;///< 设置上级路由发送函数virtual void SetTransferFunc(TransferRouteFuncPtr fp) = 0;};

2.路由处理器接口(IRouteHandler)

///////////////////////////////////////////////////////////////////////////////////< 路由处理器接口class IRouteHandler {public:///< 接收路由///< 检查接收的消息///< @return 0:正确 -1:错误///< stop是否停止后续操作(一般是在出现错误时)virtual int Check(CWrappedMsg<> *pwm,long &flag) = 0;///< @param///< break_flag: 是否终止调用其它路由处理器,1-不调用其它路由处理器 0-调用///< @return 0:未路由 1:已路由 <0:错误virtual int HandleInput(CWrappedMsg<> *pwm,int &action,int &break_flag) = 0;///< 发送路由/// @return 0:未路由 1:已路由 <0:错误virtual int HandleSend(CMsg *msg,CWrappedMsg<> **wm) = 0;///< 是否可以路由此目标的消息virtual int CanSend(short dest_type,unsigned long lo_dest_id,unsigned long hi_dest_id=0) = 0;///< 检查消息头virtual int Check(PktHead *hd,long &flag) = 0;};

3.bbox实现(主要代码)

////////////////////////////////////////////////////////////////////////////////int CBBoxPlugin::HandleInput(CWrappedMsg<> *pwm,void **pploc,int &action)  {int ret = -1;try {CMsg *msg = pwm->GetMsg();bool do_ack = msg->IsAutoAck(); ///< 包含msg->IsAck2ret = HandleInput_i(pwm,pploc,action);nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"************CBBoxPlugin::HandleInput_i()返回%d.\n",ret);/// ret: 0-交给插件处理 其它值:错误 (<0)或者转发(>0)SEMQ_ACK_HELPER *ah = (SEMQ_ACK_HELPER*)*pploc;if (action&&do_ack) {if (action==-1)semq_.Ack(ah,1);else {if (semq_.SaveAck(ah)==0) ///< @note 写入后loc中保存semq的object_id信息,Ack时需要使用semq_.Ack(ah,0);}}if (ret) { /// ret==0表示交给插件处理,其它值时释放ah对象if (ah) {delete ah;*pploc = 0;}}} catch(...) {nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"************CBBoxPlugin::HandleInput()异常.\n");}return ret;}////////////////////////////////////////////////////////////////////////////////int CBBoxPlugin::HandleInput_i(CWrappedMsg<> *pwm,void **pploc,int &action) {SEMQ_ACK_HELPER* loc = GenAckHelper(pwm);*pploc = loc;action = 1; ///< 是否需要确认检查 1-需要 0-不需要  实际上是否确认是HandleInput函数中由msg->IsAutoAck()控制CMsg *msg = pwm->msg;int tt,tt_d;unsigned long tid,tid_d; ///< 目标类型(1-机构 2-用户 3-平台),目标IDmsg->GetDest(tt,tid);msg->GetSource(tt_d,tid_d);nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"CBBoxPlugin::HandleInput_i 处理消息%d:%d(source:%d %d,dest:%d %d)...\n",msg->GetMsgType(),msg->GetMsgID(),tt_d,tid_d,tt,tid);::MSGID msgid = msg->GetMsgID();::MSGTYPE msgtype = msg->GetMsgType();///< 检查接收到的消息,确定是否需要异常情况下中断路由,是否需要做失败重做的时序控制vector<IRouteHandler*>::iterator iter = route_handler_.begin();long flag = 0;while(iter!=route_handler_.end()) {IRouteHandler *h = *iter;h->Check(pwm,flag);if (flag&IRouter::FLAG_STOP) return -1;iter++;}if (loc&&msg->IsAutoAck()) { ///< 检查是否是重复发送的消息(需要确认的消息接收后会写入Ack队列)int ret = CheckAck(loc);if (ret==-1) {action = 0;return -10;}if (ret==1) {return 10; }///< 如果没有确认信息,表示还从未接收过}if (Intercept(msg)) {///< 如果已经拦截///< 截获者不负责释放msg对象return 2;}///< 时序控制处理,仅对本服务器处理的消息if ((tt==0&&tid==0)||(flag&IRouter::FLAG_DONT_ROUTE)) { ///< 未指定目标(tt==0&&tid==0)的消息由接收者处理if (msg->IsTrusted()&&msg->IsSeqCtrl()) {int ret = redoar_.BlockCheck(msg->GetSeqControlKey());if (ret==-1) {action = 0;return -2;}if (ret==1) {if (redoar_.Save(msg,0,msg->GetSeqControlKey(),msg->GetRefKey())) {action = 0;return -3;}return 3;}}///< 本地插件处理的消息CMsg *app_msg = 0; ///< 应用消息包int rv = msg->RecoverMsg();if (rv) {return -4;}app_msg = msg->PopAppMsg();msg->Release();action = 0;pwm->Attach(app_msg);return 0;}///< 路由处理iter = route_handler_.begin();int break_flag = 0;while(iter!=route_handler_.end()) {IRouteHandler *h = *iter;int ret = h->HandleInput(pwm,action,break_flag);if (ret) {return ret;}if (break_flag)break;iter++;}if (linkto_&&transfer_fp_) {msg->Duplicate();if ((linkto_->*transfer_fp_)(msg)==0) { ///< 转移路由成功return 1;}msg->Release();action = 0;return -1;}/*///< 如果无法路由则保存到发送队列if(msg->IsTrusted()) {   if (SaveMsgForForward(CSEMQItem(msg))) {action = 0;return -8;}}*////< 消息丢弃nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"CBBoxPlugin::HandleInput_i 消息%d:%d(source:%d %d,dest:%d %d)无法路由,丢弃此消息.\n",msg->GetMsgType(),msg->GetMsgID(),tt_d,tid_d,tt,tid);return -1;}/////////////////////////////////////////////////////////////////////////////////// 根据消息目标和属性,选择发送通道/// 发送的是原始消息包(非810,812)/// @return ///   0:装包完成,调用者然后可发送///   -1: 失败int CBBoxPlugin::HandleSend(CMsg *msg,CWrappedMsg<> **wm) {try {int ret = 0;*wm = 0;int tt,tt_s;unsigned long tid,tid_s;msg->GetDest(tt,tid); msg->GetSource(tt_s,tid_s);nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"CBBoxPlugin::HandleSend 处理消息%d:%d(source:%d %d,dest:%d %d)...\n",msg->GetMsgType(),msg->GetMsgID(),tt_s,tid_s,tt,tid);if (Intercept(msg)) {///< 如果已经拦截msg->Release(); return 0; }vector<IRouteHandler*>::iterator iter = route_handler_.begin();while(iter!=route_handler_.end()) {IRouteHandler *h = *iter;int ret = h->HandleSend(msg,wm);if (ret<0) return -1;if (ret)return 0;iter++;}///< 没有路由出去的消息转给上级路由if (linkto_&&transfer_fp_) {if ((linkto_->*transfer_fp_)(msg)==0) { ///< 转移路由成功return 1;}}msg->Release();nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_WARNING,"待发送消息丢弃.\n");} catch(...) {nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"************CBBoxPlugin::HandleSend()异常.\n");}return -1;}

6.IMemData

IMemData是合并了原本地和平台内存数据库的访问接口(IAP,IDAP),应用可以选用不同的实现,如Berkeley DB和MySQL。

合并首先要统一内存对象的定义(用户,机构,服务器等).
合并时:
.IAP对应到Berkeley DB的实现(md_mdb),IDAP对应到mysql的实现(md_mysql)
.IAP,IDAP同时有的方法,语义相同,原型不同:可以同时保留,以后再清理
.IAP,IDAP只有一个实现的:如IAP实现,则需要在md_mysql中实现该方法.对于未实现的方法,统一用assert(0)表示不支持.

如对于IMemData的
virtual int BroadcastMsgToUsers(CMsg* msg, LJUSERLIST& user_list) = 0;

来自ap的BroadcastMsgToUsers。
如果需要支持mysql,则需要实现CMemDataMySQL的该方法.

CMemDataBDB::BroadcastMsgToUsers继承自CAPPlugin的实现方法.

int CAPPlugin::BroadcastMsgToUsers(CMsg* msg, LJUSERLIST& user_list){try {CWrappedMsg<> *pwm = new CWrappedMsg<>;pwm->msg = msg;MEM_USER_KEY user_key;MEM_USER_DATA* user_data;DBC* user_dbc;LJUSERLIST::iterator user_iter = user_list.begin();for(; user_iter != user_list.end(); user_iter++){user_key.user_serial_ = *user_iter;if(user_db_->Query(&user_key, sizeof(MEM_USER_KEY), (void**)&user_data, &user_dbc, MEM_LOCATE_PK) == 0){if(user_data->svr_id_ == self_->GetServerID())  //是在本地登陆的 {if(msg->GetMsgAttr()&EXTEND1_MASK)  //用户还没准备就绪也需要发送{pwm->connid.push_back(user_data->handle_);}else{if(user_data->is_ready_)  //准备就绪才发送{pwm->connid.push_back(user_data->handle_);}}}}user_db_->CloseQuery(&user_dbc);}//发送if(pwm->connid.size() > 0) {SendMsg(pwm);return 0;}//没有发送时,需要释放pwm,会自动释放msgdelete pwm;} catch(...) {throw PluginException(CE_EXCEPTION,"CMemDataMySQL::CMemDataMySQL::BroadcastMsgToUsers",SOURCEINFO);}return -1;}

CMemDataMySQL的BroadcastMsgToUsers实现。

int CMemDataMySQL::BroadcastMsgToUsers(CMsg* msg, LJUSERLIST& user_list){CWrappedMsg<> *pwm = new CWrappedMsg<>;pwm->msg = msg;LJUSERLIST::iterator user_iter = user_list.begin();for(; user_iter != user_list.end(); user_iter++) {CQQ_ORGID orgid = 0; ///< @todo LJUSERLIST传入机构IDCQQ_USERSERIAL userserial = 0;/// *user_iter; ///< @todo LJUSERLIST传入用户编号IUSERINFO  *user = GetLocalLogUser(orgid,userserial,false);if (user) {if((msg->GetMsgAttr()&EXTEND1_MASK)||user->IsReady()){pwm->connid.push_back(user->GetHandle());}user->Release();}}if (pwm->connid.size()==0) {delete pwm;return 0;}SendMsg(pwm);return 0;}


0 0
原创粉丝点击