8、Khala的设备间管理+通信
在之前的文档中,我们都是从单个设备的角度进行介绍,但在实际业务中,不同设备间存在交互行为。我们经常需要在一个设备的生命周期中查询另一个设备信息,或者向另一个设备进行通信。因此我们提供了设备管理模块来对不同设备进行查询与通信等交互管理。
目前设备管理模块提供了如下接口:
bool hasNode(uint id);
查询某个id的设备是否已经登录。
bool find(uint id, InfoNodePtr& infoNodePtr);
查询某个id的设备节点对象信息,我们可以通过InfoNodePtr节点对象查询具体节点设备的信息,或者通过InfoNodePtr.send()接口向该设备对象发送消息。
std::vector<uint> getNodeIDs(ObjectType* objectType);
查询符合该类型的所有已登录的设备节点ID,只查询该类型,不支持该类型的派生类型的查询。
std::vector<uint> getNodeIDs(const std::string& type);
查询符合该类型的所有已登录的设备节点ID,只查询该类型,不支持该类型的派生类型的查询。
template<class Type>
std::vector<uint> getAllNodeIDs(Type objectType);
查询符合该类型,或者为该类型的派生类型的所有已登录的设备节点ID,比如灯节点类型LightType,派生了日光灯DayLightType类型,调用getAllNodeIDs(LightType)将会获得所有直接为灯节点类型的ID,和派生于灯节点,如日光灯类型的ID。
template<class Type>
std::vector<uint> getAllNodeIDs(Type* objectType);
查询符合该类型,或者为该类型的派生类型的所有已登录的设备节点ID,传入类型为该类型的指针。
getAllNodeIDs()接口中,参数为ObjectType的派生类型对象或指针,实际只需获得具体的对象类型。因为C++的RTTI机制并不能实现:已知两个对象,判断这两个对象是否存在派生关系。而只能实现已知一个对象和一个具体类型,判断这个对象是否派生于这个具体类型(通过dynamic_cast<Type*>判断指针是否为空)。当然也可以通过反射和RTTI机制实现获取对象的具体类型,但是C++也不支持反射/(ㄒoㄒ)/~~。因此该接口的实现采用泛型的形式,必须通过参数传入具体的类型。所以我尝试实现很久的参数为字符串类型的std::vector<uint> getAllNodeIDs(const std::string& type)接口只能胎死腹中。当然RTTI肯定效率感人,但目前本学渣只会这种实现了/(ㄒoㄒ)/~~。
我们通过建立一个MyManageType的设备类型来测试以上接口。在ObjectType的派生类中,我们通过this->getNodeManager()接口即可获得设备管理模块,并使用以上接口。
在MyManageType类型中,我们实现onGetIDByType的消息事件,通过测试getNodeIDs来获取所有同类型的设备ID,具体实现如下:
bool MyManageType::onGetIDByType(khala::InfoNodePtr& infoNodePtr, Json::Value& msg, khala::Timestamp time) { //通过getNodeIDs获得所有与该设备类型相同的ID std::vector<uint> v = this->getNodeManager()->getNodeIDs( infoNodePtr->getNodeType()); std::stringstream ss; ss << "Get ID By Type:Ask type:" << infoNodePtr->getNodeType() << " . Get ID:"; for (std::vector<uint>::iterator it = v.begin(); it != v.end(); ++it) { ss << *it << " "; } infoNodePtr->send(ss.str()); return true; }
我们通过客户端进行测试(./example/testClient/HelloKhalaClient4.py)。我们开启两个客户端,进行login操作,并在其中一个客户端测试idByType消息事件。
此时显示存在两个设备类型为my_manage_type的设备,id分别为(懒得抄)…
我们实现onGetAllIDByObject的消息事件,通过测试getAllNodeIDs来获取所有派生于该类型的设备的ID,具体实现如下:
bool MyManageType::onGetAllIDByObject(khala::InfoNodePtr& infoNodePtr, Json::Value& msg, khala::Timestamp time) { //创建NodeType类型的对象 NodeType* tmp = new NodeType(); //传入NodeType类型,parameter is NodeType Object std::vector<uint> v = this->getNodeManager()->getAllNodeIDs(*tmp); std::stringstream ss; ss << "Get All ID By Object:Ask Object type:" << tmp->getObjectTypeName() << " . Get ID:"; for (std::vector<uint>::iterator it = v.begin(); it != v.end(); ++it) { ss << *it << " "; } infoNodePtr->send(ss.str()); //记得delete delete tmp; return true; }
同样我们在其中一个客户端测试aIdByObject消息事件。
因为我们查询的是NodeType类型,而我们创建的MyManageType类型继承于NodeType类型,因此依旧会显示这两个my_manage_type类型的id。
我们实现askLogin的消息事件,不同于系统默认的isLogin消息事件,askLogin通过测试hasNode来判断任意指定的id设备是否登录。
bool MyManageType::onAskLogin(khala::InfoNodePtr& infoNodePtr, Json::Value& msg, khala::Timestamp time){ //获得指定id uint friendId = msg[KEY_FRIEND_ID].asUInt(); std::stringstream ss; ss<<"Node ID:"<<friendId; //查询该id是否登录 if(this->getNodeManager()->hasNode(friendId)){ ss<<" is login!"; }else{ ss<<" is not login!"; } infoNodePtr->send(ss.str()); return true; }
同样我们在其中一个客户端测试askLogin消息事件。
我们自身的id为2075756572,因此我们查询另一个客户端的id:313508835,此时显示该id已经登录。
最后我们实现sendMsg消息事件,通过测试find接口,并发送消息进行通信。
bool MyManageType::onSendtoNode(khala::InfoNodePtr& infoNodePtr, Json::Value& msg, khala::Timestamp time){ //懒得输入id了,直接获取自身id uint myId = infoNodePtr->getId(); khala::InfoNodePtr myInfoNodePtr; if(this->getNodeManager()->find(myId, myInfoNodePtr)){ //如果自身id已登录(废话),则获取的myInfoNodePtr对象有效,通过该对象发送消息 myInfoNodePtr->send("test manager find success"); } return true; }
偷个小懒,自己给自己发消息,通过客户端进行测试。
接收消息成功。实际不同设备间进行通信,只需传入实际设备的id,在根据id调用find()接口,最后通过获取的InfoNodePtr调用send()即可,不同设备间进行通信就这么简单。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步