//TODO: ServiceEvent should be RemoteService and ServiceDescription void ServiceDiscovery::addedService(const RemoteService& service) { ServiceEvent event(service); ServiceConfiguration remoteConfig = service.getConfiguration(); if(mLocalService && mMode == PUBLISH) { ServiceConfiguration localConfig = mLocalService->getConfiguration(); if ( localConfig.getName() == remoteConfig.getName() && localConfig.getType() == remoteConfig.getType()) { LOG_INFO("Service published: %s", service.getName().c_str()); mPublished = true; } } { boost::unique_lock<boost::mutex> lock(mServicesMutex); ServiceDescription configuration = service.getConfiguration(); LOG_INFO("+ %s type: %s", configuration.getName().c_str(), configuration.getType().c_str()); mServices.push_back( configuration ); } { boost::unique_lock<boost::mutex> lock(mAddedComponentMutex); ServiceAddedSignal.emit( event ); } }
void ServiceDiscovery::removedService(const RemoteService& service) { ServiceEvent event(service); ServiceDescription serviceDescription = event.getServiceConfiguration(); boost::unique_lock<boost::mutex> lock(mServicesMutex); List<ServiceDescription>::iterator it = mServices.find(serviceDescription); if (it != mServices.end()) { { boost::unique_lock<boost::mutex> removalLock(mRemovedComponentMutex); ServiceDescription configuration = *it; LOG_INFO("- %s type: %s", configuration.getName().c_str(), configuration.getType().c_str()); ServiceRemovedSignal.emit( event ); } mServices.erase(it); } }
void ServiceManager::addService(Service* service, ServiceDescription& desc) { RScopeLock lock(_mutex); if (service == NULL) return; intptr_t svcPtr = (intptr_t)service; if (_svc.find(svcPtr) != _svc.end()) return; desc._channelName = service->getChannelName(); desc._svcName = service->getName(); assert(desc._channelName.length() > 0); _svc[svcPtr] = service; _localSvcDesc[svcPtr] = desc; // connect service to all nodes the manager is connected to std::set<Node>::iterator nodeIter; nodeIter = _nodes.begin(); while(nodeIter != _nodes.end()) { ((Node)*nodeIter).connect(service); nodeIter++; } // iterate continuous queries and notify other service managers about matches. std::map<std::string, ServiceFilter>::iterator filterIter = _remoteQueries.begin(); while(filterIter != _remoteQueries.end()) { if (filterIter->second.matches(desc)) { Message* foundMsg = desc.toMessage(); foundMsg->putMeta("um.rpc.filterId", filterIter->second._uuid); foundMsg->putMeta("um.rpc.type", "discovered"); foundMsg->putMeta("um.rpc.channel", desc.getChannelName()); foundMsg->putMeta("um.rpc.mgrId", _svcSub->getUUID()); _svcPub->send(foundMsg); delete foundMsg; } filterIter++; } }
void ServiceManager::removeService(Service* service) { RScopeLock lock(_mutex); if (service == NULL) return; intptr_t svcPtr = (intptr_t)service; if (_svc.find(svcPtr) == _svc.end()) return; std::set<Node>::iterator nodeIter = _nodes.begin(); while(nodeIter != _nodes.end()) { ((Node)*nodeIter).disconnect(service); nodeIter++; } assert(_localSvcDesc.find(svcPtr)!= _localSvcDesc.end()); ServiceDescription desc = _localSvcDesc[svcPtr]; // iterate continuous queries and notify other service managers about removals. std::map<std::string, ServiceFilter>::iterator filterIter = _remoteQueries.begin(); while(filterIter != _remoteQueries.end()) { if (filterIter->second.matches(desc)) { Message* removeMsg = desc.toMessage(); removeMsg->putMeta("um.rpc.filterId", filterIter->second._uuid); removeMsg->putMeta("um.rpc.type", "vanished"); removeMsg->putMeta("um.rpc.channel", desc.getChannelName()); removeMsg->putMeta("um.rpc.mgrId", _svcSub->getUUID()); _svcPub->send(removeMsg); delete removeMsg; } filterIter++; } _svc.erase(svcPtr); _localSvcDesc.erase(svcPtr); }
std::vector<ServiceDescription> ServiceDiscovery::findServices(const ServicePattern& pattern, const std::string& name_space) const { std::vector<ServiceDescription> result; List<ServiceDescription>::const_iterator it; boost::unique_lock<boost::mutex> lock(mServicesMutex); for (it = mServices.begin(); it != mServices.end(); it++) { ServiceDescription description = *it; std::string serviceprop = description.getDescription("service"); size_t namespace_begin = serviceprop.find_first_of(":") + 1; if((name_space == "*" || serviceprop.compare(namespace_begin, name_space.size(), name_space) == 0) && pattern.matchDescription(description) ) { result.push_back(description); } } return result; }
void ServiceDiscovery::updatedService(const RemoteService& service) { ServiceDescription desc = service.getConfiguration(); boost::unique_lock<boost::mutex> lock(mServicesMutex); List<ServiceDescription>::iterator it; for(it = mServices.begin(); it != mServices.end(); it++) { if( desc.compareWithoutTXT(*it) ) { std::vector<std::string> labels = desc.getLabels(); for(unsigned int i = 0; i < labels.size(); i++) { it->setDescription(labels[i], desc.getDescription(labels[i])); } LOG_INFO("Updated service: %s", service.getName().c_str()); } } }
void ServiceDiscovery::update(const ServiceDescription& desc) { if(mLocalService != NULL) { std::list<std::string> raw_desc = desc.getRawDescriptions(); UniqueClientLock lock; mLocalService->updateStringList(raw_desc); LOG_INFO("Updated local service: %s", mLocalService->getName().c_str()); } else { LOG_FATAL("Service Discovery tries to update a description on a non-started local service.\n"); throw std::runtime_error("Service Discovery tries to update a description on a non-started local service"); } }
void ServiceManager::removeService(Service* service) { ScopeLock lock(&_mutex); if (service == NULL) return; intptr_t svcPtr = (intptr_t)service; if (_svc.find(svcPtr) == _svc.end()) return; std::set<Node*>::iterator nodeIter = _nodes.begin(); while(nodeIter != _nodes.end()) { (*nodeIter++)->disconnect(service); } assert(_localSvcDesc.find(svcPtr)!= _localSvcDesc.end()); ServiceDescription* desc = _localSvcDesc[svcPtr]; // iterate continuous queries and notify other service managers about removals. std::map<string, ServiceFilter*>::iterator filterIter = _remoteQueries.begin(); while(filterIter != _remoteQueries.end()) { if (filterIter->second->matches(desc)) { Message* removeMsg = desc->toMessage(); removeMsg->setMeta("filterId", filterIter->second->_uuid); removeMsg->setMeta("type", "serviceDiscRemoved"); removeMsg->setMeta("desc:channel", desc->getChannelName()); _svcPub->send(removeMsg); delete removeMsg; } filterIter++; } _svc.erase(svcPtr); _localSvcDesc.erase(svcPtr); }
int main(int argc, char** argv) { Node n; ServiceManager svcMgr; Discovery disc(Discovery::MDNS); disc.add(n); // set some random properties to query for ServiceDescription echoSvcDesc; echoSvcDesc.setProperty("host", Host::getHostId()); echoSvcDesc.setProperty("someString", "this is some random string with 123 numbers inside"); echoSvcDesc.setProperty("someNumber", "1"); EchoService* echoSvc = new EchoService(); svcMgr.addService(echoSvc, echoSvcDesc); PingService* pingSvc = new PingService(); svcMgr.addService(pingSvc); n.connect(&svcMgr); while(true) Thread::sleepMs(1000); }
bool ServiceDescription::operator==(const ServiceDescription& other) const { if(!compareWithoutTXT(other)) return false; std::vector<std::string> labels = this->getLabels(); int labelsSize = labels.size(); for(int i = 0; i < labelsSize; i++) { std::string label = labels_[i]; if(this->getDescription(label) != other.getDescription(label)) return false; } return true; }
bool ServiceDescription::compareWithoutTXT(const ServiceDescription& other) const { if( interfaceIndex_ != other.getInterfaceIndex() && !(interfaceIndex_ == AVAHI_IF_UNSPEC || other.getInterfaceIndex() == AVAHI_IF_UNSPEC)) return false; if(protocol_ != other.getProtocol() && !(protocol_ == AVAHI_PROTO_UNSPEC || other.getProtocol() == AVAHI_PROTO_UNSPEC)) return false; if( getName() != other.getName()) return false; if( getType() != other.getType()) return false; // Compare domains and ignore consider that "" defaults to 'local' std::string td1 = (domain_ == "" || domain_ == "local") ? "" : domain_; std::string td2 = (other.getDomain() == "" || other.getDomain() == "local") ? "" : other.getDomain(); if (td1 != td2) return false; return true; }
void ServiceManager::receive(Message* msg) { RScopeLock lock(_mutex); // is this a response for one of our requests? if (msg->getMeta().find("um.rpc.respId") != msg->getMeta().end()) { std::string respId = msg->getMeta("um.rpc.respId"); if (_findRequests.find(respId) != _findRequests.end()) { // put message into responses and signal waiting thread _findResponses[respId] = new Message(*msg); _findRequests[respId]->signal(); } } // is someone simply asking for a service via find? if (msg->getMeta().find("um.rpc.type") != msg->getMeta().end() && msg->getMeta("um.rpc.type").compare("discover") == 0) { ServiceFilter filter(msg); std::set<ServiceDescription> foundSvcs = findLocal(filter); if (foundSvcs.size() > 0) { ServiceDescription svcDesc = (*(foundSvcs.begin())); Message* foundMsg = svcDesc.toMessage(); foundMsg->setReceiver(msg->getMeta("um.rpc.mgrId")); foundMsg->putMeta("um.rpc.respId", msg->getMeta("um.rpc.reqId")); foundMsg->putMeta("um.rpc.mgrId", _svcSub->getUUID()); // if (_svcPub->isPublishingTo(msg->getMeta("um.rpc.mgrId"))) { _svcPub->send(foundMsg); // } else { // // queue message and send in welcome // _pendingMessages[msg->getMeta("um.rpc.mgrId")].push_back(std::make_pair(Thread::getTimeStampMs(), foundMsg)); // } delete foundMsg; } } // is this the start of a continuous query? if (msg->getMeta().find("um.rpc.type") != msg->getMeta().end() && msg->getMeta("um.rpc.type").compare("startDiscovery") == 0) { ServiceFilter filter(msg); _remoteQueries[filter.getUUID()] = filter; UM_LOG_INFO("Received query for '%s'", filter._svcName.c_str()); // do we have such a service? std::set<ServiceDescription> foundSvcs = findLocal(filter); std::set<ServiceDescription>::iterator svcDescIter = foundSvcs.begin(); while(svcDescIter != foundSvcs.end()) { Message* foundMsg = svcDescIter->toMessage(); foundMsg->setReceiver(msg->getMeta("um.rpc.mgrId")); foundMsg->putMeta("um.rpc.filterId", filter.getUUID()); foundMsg->putMeta("um.rpc.type", "discovered"); foundMsg->putMeta("um.rpc.mgrId", _svcSub->getUUID()); _svcPub->send(foundMsg); delete foundMsg; svcDescIter++; } } // is this the end of a continuous query? if (msg->getMeta().find("um.rpc.type") != msg->getMeta().end() && msg->getMeta("um.rpc.type").compare("stopDiscovery") == 0) { ServiceFilter filter(msg); if (_remoteQueries.find(filter.getUUID()) != _remoteQueries.end()) { _remoteQueries.erase(filter.getUUID()); } } // is this a reply to a continuous service query? if (msg->getMeta().find("um.rpc.type") != msg->getMeta().end() && (msg->getMeta("um.rpc.type").compare("discovered") == 0 || msg->getMeta("um.rpc.type").compare("vanished") == 0)) { // _svcQueries comparator uses filter uuid ServiceFilter keyFilter(""); keyFilter._uuid = msg->getMeta("um.rpc.filterId"); if (_localQueries.find(keyFilter) != _localQueries.end()) { ResultSet<ServiceDescription>* listener = _localQueries[keyFilter]; assert(msg->getMeta("um.rpc.desc.channel").size() > 0); assert(msg->getMeta("um.rpc.mgrId").size() > 0); std::string svcChannel = msg->getMeta("um.rpc.desc.channel"); std::string managerId = msg->getMeta("um.rpc.mgrId"); if (_remoteSvcDesc.find(managerId) == _remoteSvcDesc.end() || _remoteSvcDesc[managerId].find(svcChannel) == _remoteSvcDesc[managerId].end()) { _remoteSvcDesc[managerId][svcChannel] = ServiceDescription(msg); _remoteSvcDesc[managerId][svcChannel]._svcManager = this; } assert(_remoteSvcDesc.find(managerId) != _remoteSvcDesc.end()); assert(_remoteSvcDesc[managerId].find(svcChannel) != _remoteSvcDesc[managerId].end()); if (msg->getMeta("um.rpc.type").compare("discovered") == 0) { listener->added(_remoteSvcDesc[managerId][svcChannel]); } else { listener->removed(_remoteSvcDesc[managerId][svcChannel]); _remoteSvcDesc[managerId].erase(svcChannel); } } } }
void ServiceManager::receive(Message* msg) { ScopeLock lock(&_mutex); // is this a response for one of our requests? if (msg->getMeta().find("respId") != msg->getMeta().end()) { string respId = msg->getMeta("respId"); if (_findRequests.find(respId) != _findRequests.end()) { _findResponses[respId] = new Message(*msg); _findRequests[respId].signal(); } } // is someone asking for a service? if (msg->getMeta().find("type") != msg->getMeta().end() && msg->getMeta("type").compare("serviceDisc") == 0) { ServiceFilter* filter = new ServiceFilter(msg); std::set<ServiceDescription*> foundSvcs = findLocal(filter); delete filter; if (foundSvcs.size() > 0) { ServiceDescription* svcDesc = (*(foundSvcs.begin())); Message* foundMsg = svcDesc->toMessage(); foundMsg->setMeta("respId", msg->getMeta("reqId")); foundMsg->setMeta("desc:channel", svcDesc->getChannelName()); _svcPub->send(foundMsg); delete foundMsg; } } // is this the start of a continuous query? if (msg->getMeta().find("type") != msg->getMeta().end() && msg->getMeta("type").compare("serviceDiscStart") == 0) { ServiceFilter* filter = new ServiceFilter(msg); _remoteQueries[filter->_uuid] = filter; // do we have such a service? std::set<ServiceDescription*> foundSvcs = findLocal(filter); std::set<ServiceDescription*>::iterator svcDescIter = foundSvcs.begin(); while(svcDescIter != foundSvcs.end()) { if (filter->matches(*svcDescIter)) { Message* foundMsg = (*svcDescIter)->toMessage(); foundMsg->setMeta("filterId", filter->_uuid); foundMsg->setMeta("type", "serviceDiscFound"); foundMsg->setMeta("desc:channel", (*svcDescIter)->getChannelName()); _svcPub->send(foundMsg); delete foundMsg; } svcDescIter++; } } // is this the end of a continuous query? if (msg->getMeta().find("type") != msg->getMeta().end() && msg->getMeta("type").compare("serviceDiscStop") == 0) { ServiceFilter* filter = new ServiceFilter(msg); if (_remoteQueries.find(filter->_uuid) != _remoteQueries.end()) { delete _remoteQueries[filter->_uuid]; _remoteQueries.erase(filter->_uuid); } delete filter; } // is this a reply to a continuous service query? if (msg->getMeta().find("type") != msg->getMeta().end() && (msg->getMeta("type").compare("serviceDiscFound") == 0 || msg->getMeta("type").compare("serviceDiscRemoved") == 0)) { // _svcQueries comparator uses filter uuid ServiceFilter* keyFilter = new ServiceFilter(""); keyFilter->_uuid = msg->getMeta("filterId"); if (_localQueries.find(keyFilter) != _localQueries.end()) { ResultSet<ServiceDescription>* listener = _localQueries[keyFilter]; assert(msg->getMeta("desc:channel").size() > 0); if (_remoteSvcDesc.find(msg->getMeta("desc:channel")) == _remoteSvcDesc.end()) _remoteSvcDesc[msg->getMeta("desc:channel")] = shared_ptr<ServiceDescription>(new ServiceDescription(msg)); if (msg->getMeta("type").compare("serviceDiscFound") == 0) { listener->added(_remoteSvcDesc[msg->getMeta("desc:channel")]); } else { listener->removed(_remoteSvcDesc[msg->getMeta("desc:channel")]); _remoteSvcDesc.erase(msg->getMeta("desc:channel")); } } delete keyFilter; } }
bool ServiceDescription::operator==(const ServiceDescription& cmp) const { return (m_id == cmp.id()); }