Package master_discovery_fkie :: Module master_info
[frames] | no frames]

Source Code for Module master_discovery_fkie.master_info

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  import time 
 34   
 35  import roslib; roslib.load_manifest('master_discovery_fkie') 
 36  import rospy 
37 38 -class NodeInfo(object):
39 ''' 40 The NodeInfo class stores informations about a ROS node. 41 '''
42 - def __init__(self, name, masteruri):
43 ''' 44 Creates a new NodeInfo for a node with given name. 45 @param name: the name of the node 46 @type name: C{str} 47 @param masteruri: the URI of the ROS master, where the node is registered. 48 This masteruri will be used to determine, whether the ROS master and the 49 node are running on the same machine. 50 @type masteruri: C{str} 51 ''' 52 self.__name = name 53 self.__masteruri = masteruri 54 self.__org_masteruri = masteruri 55 self.__uri = None 56 self.pid = None 57 '''@ivar: the process id of the node. Invalid id has a C{None} value''' 58 self.__local = False 59 self._publishedTopics = [] 60 self._subscribedTopics = [] 61 self._services = []
62 63 @property
64 - def name(self):
65 ''' 66 Returns the name of the node. 67 @rtype: C{str} 68 ''' 69 return self.__name
70 71 @property
72 - def uri(self):
73 ''' 74 Returns the URI of the RPC API of the node. 75 @rtype: C{str} 76 ''' 77 return self.__uri
78 79 @uri.setter
80 - def uri(self, uri):
81 ''' 82 Sets the URI of the RPC API of the node. 83 ''' 84 self.__uri = uri 85 self.__local = NodeInfo.local_(self.__masteruri, self.__org_masteruri, self.__uri)
86 87 @property
88 - def masteruri(self):
89 ''' 90 Returns the URI of the ROS master where the node is registered. 91 @rtype: C{str} 92 ''' 93 return self.__org_masteruri
94 95 @masteruri.setter
96 - def masteruri(self, uri):
97 ''' 98 Sets the ROS master URI. 99 ''' 100 self.__org_masteruri = uri 101 self.__local = NodeInfo.local_(self.__masteruri, self.__org_masteruri, self.__uri)
102 103 @property
104 - def isLocal(self):
105 ''' 106 Returns C{True} if the node and the ROS master are running on the same machine. 107 @rtype: C{boolean} 108 ''' 109 return self.__local
110 111 @property
112 - def publishedTopics(self):
113 ''' 114 Returns the list of all published topics by this node. 115 @rtype: C{[str, ...]} 116 ''' 117 return self._publishedTopics
118 119 @publishedTopics.setter
120 - def publishedTopics(self, name):
121 ''' 122 Append a new published topic to this node. 123 @param name: the name of the topic 124 @type name: C{str} 125 ''' 126 try: 127 if isinstance(name, list): 128 del self._publishedTopics 129 self._publishedTopics = name 130 else: 131 self._publishedTopics.index(name) 132 except ValueError: 133 self._publishedTopics.append(name)
134 135 # @publishedTopics.deleter 136 # def publishedTopics(self): 137 # del self._publishedTopics 138 139 @property
140 - def subscribedTopics(self):
141 ''' 142 Returns the list of all subscribed topics by this node. 143 @rtype: C{[str, ...]} 144 ''' 145 return self._subscribedTopics
146 147 @subscribedTopics.setter
148 - def subscribedTopics(self, name):
149 ''' 150 Append a new subscribed topic to this node. 151 @param name: the name of the topic 152 @type name: C{str} 153 ''' 154 try: 155 if isinstance(name, list): 156 del self._subscribedTopics 157 self._subscribedTopics = name 158 else: 159 self._subscribedTopics.index(name) 160 except ValueError: 161 self._subscribedTopics.append(name)
162 163 # @subscribedTopics.deleter 164 # def subscribedTopics(self): 165 # del self._subscribedTopics 166 167 @property
168 - def services(self):
169 ''' 170 Returns the list of all services provided by this node. 171 @rtype: C{[str, ...]} 172 ''' 173 return self._services
174 175 @services.setter
176 - def services(self, name):
177 ''' 178 Append a new service to this node. 179 @param name: the name of the topic 180 @type name: C{str} 181 ''' 182 try: 183 if isinstance(name, list): 184 del self._services 185 self._services = name 186 else: 187 self._services.index(name) 188 except ValueError: 189 self._services.append(name)
190 191 # @services.deleter 192 # def services(self): 193 # del self._services 194
195 - def copy(self):
196 ''' 197 Creates a copy this object and returns it. 198 @rtype: L{NodeInfo} 199 ''' 200 result = NodeInfo(self.name, self.masteruri) 201 result.uri = ''.join([self.uri]) if not self.uri is None else None 202 result.pid = self.pid 203 result._publishedTopics = list(self._publishedTopics) 204 result._subscribedTopics = list(self._subscribedTopics) 205 result._services = list(self._services) 206 return result
207 208 @staticmethod
209 - def local_(masteruri, org_masteruri, uri):
210 result = False 211 try: 212 from urlparse import urlparse 213 om = urlparse(masteruri) 214 on = urlparse(uri) 215 result = (om.hostname == on.hostname) and (masteruri == org_masteruri) 216 except: 217 pass 218 return result
219
220 221 -class TopicInfo(object):
222 ''' 223 The TopicInfo class stores informations about a ROS topic. 224 '''
225 - def __init__(self, name):
226 ''' 227 Creates a new TopicInfo for a topic with given name. 228 @param name: the name of the topic 229 @type name: C{str} 230 ''' 231 self.__name = name 232 self.type = None 233 '''@ivar: the type of the topic. (Default: None)''' 234 self._publisherNodes = [] 235 self._subscriberNodes = []
236 237 @property
238 - def name(self):
239 ''' 240 Returns the name of the topic. 241 @rtype: C{str} 242 ''' 243 return self.__name
244 245 @property
246 - def publisherNodes(self):
247 ''' 248 Returns the list with node names witch are publishing to this topic. 249 @rtype: C{[str,...]} 250 ''' 251 return list(self._publisherNodes)
252 253 @publisherNodes.setter
254 - def publisherNodes(self, name):
255 ''' 256 Append a new publishing node to this topic. 257 ''' 258 try: 259 if isinstance(name, list): 260 del self._publisherNodes 261 self._publisherNodes = name 262 else: 263 self._publisherNodes.index(name) 264 except ValueError: 265 self._publisherNodes.append(name)
266 267 # @publisherNodes.deleter 268 # def publisherNodes(self): 269 # del self._publisherNodes 270 271 @property
272 - def subscriberNodes(self):
273 ''' 274 Returns the list with node names witch are subscribed to this topic. 275 @rtype: C{[str,...]} 276 ''' 277 return list(self._subscriberNodes)
278 279 @subscriberNodes.setter
280 - def subscriberNodes(self, name):
281 ''' 282 Append a new subscribing node to this topic. 283 ''' 284 try: 285 if isinstance(name, list): 286 del self._subscriberNodes 287 self._subscriberNodes = name 288 else: 289 self._subscriberNodes.index(name) 290 except ValueError: 291 self._subscriberNodes.append(name)
292 293 # @subscriberNodes.deleter 294 # def subscriberNodes(self): 295 # del self._subscriberNodes 296
297 - def copy(self):
298 ''' 299 Creates a copy this object and returns it. 300 @rtype: L{TopicInfo} 301 ''' 302 result = TopicInfo(self.name) 303 result.type = self.type 304 result._publisherNodes = list(self._publisherNodes) 305 result._subscriberNodes = list(self._subscriberNodes) 306 return result
307
308 309 -class ServiceInfo(object):
310 ''' 311 The ServiceInfo class stores informations about a ROS service. 312 '''
313 - def __init__(self, name, masteruri):
314 ''' 315 Creates a new instance of the ServiceInfo. 316 @param name: the name of the service 317 @type name: C{str} 318 @param masteruri: the URI of the ROS master, where the service is registered. 319 This masteruri will be used to determine, whether the ROS master and the 320 service are running on the same machine. 321 @type masteruri: C{str} 322 ''' 323 self.__name = name 324 self.__masteruri = masteruri 325 self.__org_masteruri = masteruri 326 self.__uri = None 327 self.__local = False 328 self.type = None 329 '''@ivar: the type of the service. (Default: None)''' 330 self.__service_class = None 331 self.args = None 332 self.__serviceProvider = []
333 334 @property
335 - def name(self):
336 ''' 337 Returns the name of the service. 338 @rtype: C{str} 339 ''' 340 return self.__name
341 342 @property
343 - def uri(self):
344 ''' 345 Returns the URI of the RPC API of the service 346 @rtype: C{str} 347 ''' 348 return self.__uri
349 350 @uri.setter
351 - def uri(self, uri):
352 ''' 353 Sets the uri of the service RPC interface and determine whether this service 354 and the ROS master are running on the same machine. 355 @param uri: The URI of the service RPC interface 356 @type uri: C{str} 357 ''' 358 self.__uri = uri 359 self.__local = NodeInfo.local_(self.__masteruri, self.__org_masteruri, self.__uri)
360 361 @property
362 - def masteruri(self):
363 ''' 364 Returns the URI of the ROS master of the service 365 @rtype: C{str} 366 ''' 367 return self.__org_masteruri
368 369 @masteruri.setter
370 - def masteruri(self, uri):
371 ''' 372 Sets the uri of the origin ROS master and determine whether this service 373 and the ROS master are running on the same machine. 374 @param uri: The URI of the ROS master 375 @type uri: C{str} 376 ''' 377 self.__org_masteruri = uri 378 self.__local = NodeInfo.local_(self.__masteruri, self.__org_masteruri, self.__uri)
379 380 @property
381 - def isLocal(self):
382 ''' 383 Returns C{True}, if this service and the master are on the same machine. This 384 will be determine on setting the uri-parameter. 385 @rtype: C{boolean} 386 ''' 387 return self.__local
388 389 @property
390 - def serviceProvider(self):
391 ''' 392 Return the list of the node names, which provide this service. 393 @rtype: C{[str, ...]} 394 ''' 395 return self.__serviceProvider
396 397 @serviceProvider.setter
398 - def serviceProvider(self, name):
399 ''' 400 Adds a new service provider, if no one with given name exists. 401 @param name: name of the new service provider 402 @type name: C{str} 403 ''' 404 try: 405 self.__serviceProvider.index(name) 406 except ValueError: 407 self.__serviceProvider.append(name)
408 409 @serviceProvider.deleter
410 - def serviceProvider(self):
411 del self.__serviceProvider
412 413
414 - def get_service_class(self, allow_get_type=False):
415 ''' 416 Get the service class using the type of the service. NOTE: this 417 method is from 'rosservice' and changed to avoid a probe call to the service. 418 @param allow_get_type: allow to connect to service and get the type if the 419 type is not valid (in case of other host e.g.) 420 @type allow_get_type: C{boolean} 421 @return: service class 422 @rtype: ServiceDefinition: service class 423 @raise ROSServiceException: if service class cannot be retrieved 424 ''' 425 if not self.__service_class is None: 426 return self.__service_class 427 428 type = self.type 429 # request the type if it is empty and allowed 430 if not type and allow_get_type and self.uri: 431 dest_addr = dest_port = None 432 try: 433 dest_addr, dest_port = rospy.parse_rosrpc_uri(self.uri) 434 except: 435 pass 436 else: 437 import socket 438 import cStringIO 439 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 440 try: 441 # connect to service and probe it to get the headers 442 s.settimeout(0.5) 443 s.connect((dest_addr, dest_port)) 444 header = { 'probe':'1', 'md5sum':'*', 445 'callerid':rospy.get_name(), 'service':self.name} 446 roslib.network.write_ros_handshake_header(s, header) 447 type = roslib.network.read_ros_handshake_header(s, cStringIO.StringIO(), 2048) 448 type = type['type'] 449 except socket.error: 450 pass 451 except: 452 pass 453 finally: 454 if s is not None: 455 s.close() 456 457 import rosservice 458 if not type: 459 raise rosservice.ROSServiceException("Not valid type of service [%s]."%str(type)) 460 461 # get the Service class so we can populate the request 462 service_class = roslib.message.get_service_class(type) 463 464 # #1083: roscpp services are currently returning the wrong type 465 if service_class and self.type.endswith('Request') and \ 466 not hasattr(service_class, "_request_class"): 467 type = type[:-7] 468 service_class = roslib.message.get_service_class(type) 469 470 if service_class is None: 471 pkg = roslib.names.resource_name_package(self.type) 472 raise rosservice.ROSServiceException("Unable to load type [%s].\n"%self.type+ 473 "Have you typed 'make' in [%s]?"%pkg) 474 self.__service_class = service_class 475 return service_class
476
477 478 -class MasterInfo(object):
479 ''' 480 The MasterInfo class stores informations about a ROS master. 481 Not thread safe! 482 '''
483 - def __init__(self, masteruri, mastername = None):
484 ''' 485 Creates a new instance of the MasterInfo. The mastername will be extracted 486 from the masterui, if no name is given. 487 @param masteruri: The URI of the corresponding master 488 @type masteruri: str 489 @param mastername: The name of the ROS master. If no one is given, it will be 490 extracted from the masteruri. 491 @type mastername: str or None (Default: None) 492 ''' 493 self.__masteruri = masteruri 494 self.__mastername = mastername 495 if mastername is None: 496 from urlparse import urlparse 497 o = urlparse(self.__masteruri) 498 self.__mastername = o.hostname 499 self.__nodelist = {} 500 self.__topiclist = {} 501 self.__servicelist = {} 502 self.__timestamp = 0 503 self.__timestamp_local = 0 504 self.check_ts = 0 505 '''@ivar: the last time, when the state of the ROS master retrieved'''
506 507 @staticmethod
508 - def from_list(l):
509 ''' 510 Creates a new instance of the MasterInfo from given list. 511 @see: L{listedState()} 512 @param l: the list returned by listedState() 513 @type l: list 514 @return: the new instance of the MasterInfo filled from list. 515 @rtype: MasterInfo 516 ''' 517 if l is None: 518 return None 519 result = MasterInfo(l[2], l[3]) 520 result.timestamp = float(l[0]) 521 result.timestamp_local = float(l[1]) 522 publishers = l[4] 523 subscribers = l[5] 524 services = l[6] 525 topicTypes = l[7] 526 nodes = l[8] 527 serviceProvider = l[9] 528 # set the publishers 529 for pub, nodelist in publishers: 530 result.topics = pub 531 for n in nodelist: 532 result.nodes = n 533 result.getNode(n).publishedTopics = pub 534 result.getTopic(pub).publisherNodes = n 535 # set the subscribers 536 for sub, nodelist in subscribers: 537 result.topics = sub 538 for n in nodelist: 539 result.nodes = n 540 result.getNode(n).subscribedTopics = sub 541 result.getTopic(sub).subscriberNodes = n 542 # set the services 543 for s, provider in services: 544 result.services = s 545 for n in provider: 546 result.nodes = n 547 result.getNode(n).services = s 548 result.getService(s).serviceProvider = n 549 # set the topic types 550 for topic, type in topicTypes: 551 result.topics = topic 552 result.getTopic(topic).type = type 553 # set the node informations 554 for nodename, uri, masteruri, pid, local in nodes: 555 result.nodes = nodename 556 result.getNode(nodename).uri = uri 557 result.getNode(nodename).masteruri = masteruri 558 result.getNode(nodename).pid = pid 559 # set the service informations 560 for servicename, uri, masteruri, type, local in serviceProvider: 561 result.services = servicename 562 result.getService(servicename).uri = uri 563 result.getService(servicename).masteruri = masteruri 564 result.getService(servicename).type = type 565 return result
566 567 @property
568 - def mastername(self):
569 ''' 570 Returns the name of the ROS master. In most cases the ROS master name is the 571 name of the host, where the ROS master running. Although it can differ. 572 @rtype: C{str} 573 ''' 574 return self.__mastername
575 576 @property
577 - def masteruri(self):
578 ''' 579 Returns the URI of the ROS master. 580 @rtype: C{str} 581 ''' 582 return self.__masteruri
583 584 @property
585 - def timestamp(self):
586 ''' 587 The timestamp when this MasterInfo was first time filled with the 588 information. See L{self.check_ts} to get the time, when the information was 589 compared with the data of ROS Master. 590 @rtype: C{float} 591 ''' 592 return self.__timestamp
593 594 @timestamp.setter
595 - def timestamp(self, ts):
596 ''' 597 Sets the timestamp of this instance 598 @param ts: the new timestamp 599 @type ts: C{float} 600 ''' 601 self.__timestamp = ts 602 self.check_ts = ts 603 self.__timestamp_local = ts
604 605 @property
606 - def timestamp_local(self):
607 ''' 608 The timestamp when this MasterInfo was first time filled with the 609 information. See L{self.check_ts} to get the time, when the information was 610 compared with the data of ROS Master. 611 @rtype: C{float} 612 ''' 613 return self.__timestamp_local
614 615 @timestamp_local.setter
616 - def timestamp_local(self, ts):
617 ''' 618 Sets the timestamp of this instance 619 @param ts: the new timestamp 620 @type ts: C{float} 621 ''' 622 self.__timestamp_local = ts
623 624 @property
625 - def nodes(self):
626 ''' 627 Returns the dictionary with node names and corresponding instances of L{NodeInfo}. 628 @rtype: C{dict(str:L{NodeInfo}, ...)} 629 ''' 630 return self.__nodelist
631 632 @nodes.setter
633 - def nodes(self, name):
634 ''' 635 Adds a new L{NodeInfo} with given name. 636 @note: If the NodeInfo already exists, do nothing. 637 @param name: the name of new L{NodeInfo} 638 @type name: C{str} 639 ''' 640 if (name is None) or not name: 641 return None 642 if not (name in self.__nodelist): 643 self.__nodelist[name] = NodeInfo(name, self.__masteruri)
644 645 @property
646 - def node_names(self):
647 ''' 648 Returns the list with node names 649 @rtype: C{[str, ...]} 650 ''' 651 # @return: the list with node names 652 return self.__nodelist.keys()
653 654 @property
655 - def node_uris(self):
656 ''' 657 Returns the list with node URI's. 658 @rtype: C{[str, ...]} 659 ''' 660 uris = [] 661 for node in self.__nodelist.itervalues(): 662 uris.append(node.uri) 663 return uris
664 665 @property
666 - def topics(self):
667 ''' 668 Returns the dictionary with topic names and corresponding L{TopicInfo} instances. 669 @rtype: C{dict(str:L{TopicInfo}, ...)} 670 ''' 671 return self.__topiclist
672 673 @topics.setter
674 - def topics(self, name):
675 ''' 676 Adds a new TopicInfo with given name. If the L{TopicInfo} already exists, do 677 nothing. 678 @param name: the name of new L{TopicInfo} 679 @type name: C{str} 680 ''' 681 if (name is None) or not name: 682 return None 683 if not (name in self.__topiclist): 684 self.__topiclist[name] = TopicInfo(name)
685 686 @property
687 - def topic_names(self):
688 ''' 689 Returns the list with topic names. 690 @rtype: C{[str, ...]} 691 ''' 692 return self.__topiclist.keys()
693 694 @property
695 - def services(self):
696 ''' 697 Returns the dictionary with service names and corresponding L{ServiceInfo} instances. 698 @rtype: C{dict(str:L{ServiceInfo}, ...)} 699 ''' 700 return self.__servicelist
701 702 @services.setter
703 - def services(self, name):
704 ''' 705 Adds a new L{ServiceInfo} with given name. If the L{ServiceInfo} already exists, do 706 nothing. 707 @param name: the name of new L{ServiceInfo} 708 @type name: C{str} 709 ''' 710 if (name is None) or not name: 711 return None 712 if not (name in self.__servicelist): 713 self.__servicelist[name] = ServiceInfo(name, self.__masteruri)
714 715 @property
716 - def service_names(self):
717 ''' 718 Returns the list with service names. 719 @rtype: C{[str, ...]} 720 ''' 721 return self.__servicelist.keys()
722 723 @property
724 - def service_uris(self):
725 ''' 726 Returns the list with service URI's. 727 @rtype: C{[str, ...]} 728 ''' 729 uris = [] 730 for service in self.__servicelist.itervalues(): 731 uris.append(service.uri) 732 return uris
733
734 - def getNode(self, name):
735 ''' 736 @param name: the name of the node 737 @type name: str 738 @return: the instance of the L{NodeInfo} with given name 739 @rtype: L{NodeInfo} or C{None} 740 ''' 741 if (name is None) or not name: 742 return None 743 return self.__nodelist.get(name, None)
744
745 - def getNodeEndsWith(self, suffix):
746 ''' 747 Returns the node, which name ends with given suffix 748 @param suffix: the end of the name 749 @type suffix: C{str} 750 @return: the instance of the L{NodeInfo} with with given suffix 751 @rtype: L{NodeInfo} or C{None} 752 ''' 753 if (suffix is None) or not suffix: 754 return None 755 for name, node in self.__nodelist.items(): 756 if name.endswith(suffix): 757 return node 758 return None
759
760 - def getTopic(self, name):
761 ''' 762 @param name: the name of the topic 763 @type name: C{str} 764 @return: the instance of the L{TopicInfo} with given name 765 @rtype: L{NodeInfo} or C{None} 766 ''' 767 if (name is None) or not name: 768 return None 769 return self.__topiclist.get(name, None)
770
771 - def getService(self, name):
772 ''' 773 @param name: the name of the service 774 @type name: C{str} 775 @return: the instance of the L{ServiceInfo} with given name 776 @rtype: L{ServiceInfo} or C{None} 777 ''' 778 if (name is None) or not name: 779 return None 780 return self.__servicelist.get(name, None)
781
782 - def __eq__(self, other):
783 ''' 784 Compares the master state with other master state. The timestamp will not be 785 compared. 786 @param other: the another L{MasterInfo} instance. 787 @type other: L{MasterInfo} 788 @return: True, if the states are equal. 789 @rtype: C{boolean} 790 ''' 791 # import os ################### 792 # cputimes = os.times() ################### 793 # cputime_init = cputimes[0] + cputimes[1] ################### 794 # try: 795 if (other is None): 796 return False 797 if (self.masteruri != other.masteruri): 798 return False 799 if (set(self.node_uris) ^ set(other.node_uris)): 800 return False 801 # if (set(self.node_names) ^ set(other.node_names)): 802 # return False 803 # if (set(self.service_names) ^ set(other.service_names)): 804 # return False 805 if (set(self.service_uris) ^ set(other.service_uris)): 806 return False 807 if (set(self.topic_names) ^ set(other.topic_names)): 808 return False 809 # test for changes of each node parameter 810 for name in self.node_names: 811 n1 = self.getNode(name) 812 n2 = other.getNode(name) 813 if not n1 is None and not n2 is None: 814 if n1.pid != n2.pid: 815 return False 816 # if n1.uri != n2.uri: 817 # return False 818 if set(n1.publishedTopics) ^ set(n2.publishedTopics): 819 return False 820 if set(n1.subscribedTopics) ^ set(n2.subscribedTopics): 821 return False 822 if set(n1.services) ^ set(n2.services): 823 return False 824 return True
825 # finally: 826 # cputimes = os.times() ################### 827 # print "EQ:", (cputimes[0] + cputimes[1] - cputime_init), ", count nodes:", len(self.node_names) ################### 828 829
830 - def __ne__(self, other):
831 return not self.__eq__(other)
832
833 - def has_local_changes(self, other):
834 ''' 835 Compares the master state with other master state. The timestamp will not be 836 compared. 837 @param other: the another L{MasterInfo} instance. 838 @type other: L{MasterInfo} 839 @return a tupel with two boolean values (all equal, only local equal) 840 @rtype: (boolean, boolean) 841 ''' 842 # import os ################### 843 # cputimes = os.times() ################### 844 # cputime_init = cputimes[0] + cputimes[1] ################### 845 # try: 846 if (other is None): 847 return True 848 if (self.masteruri != other.masteruri): 849 return True 850 # test for nodes 851 node_names = list((set(self.node_names) | set(other.node_names))) 852 for name in node_names: 853 n1 = self.getNode(name) 854 n2 = other.getNode(name) 855 if not n1 is None and not n2 is None: 856 local = n1.isLocal 857 if local: 858 if n1.pid != n2.pid: 859 return True 860 if n1.uri != n2.uri: 861 return True 862 if set(n1.publishedTopics) ^ set(n2.publishedTopics): 863 return True 864 if set(n1.subscribedTopics) ^ set(n2.subscribedTopics): 865 return True 866 if set(n1.services) ^ set(n2.services): 867 return True 868 elif not n1 is None: 869 if n1.isLocal: 870 return True 871 elif not n2 is None: 872 if n2.isLocal: 873 return True 874 875 # test for services 876 service_names = list(set(self.service_uris) | set(other.service_uris)) 877 for name in service_names: 878 s1 = self.getService(name) 879 s2 = other.getService(name) 880 if not s1 is None and not s2 is None: 881 local = s1.isLocal or s2.isLocal 882 if s1.uri != s2.uri: 883 return True 884 elif not s1 is None: 885 if s1.isLocal: 886 return True 887 elif not s2 is None: 888 if s2.isLocal: 889 return True 890 return False
891 # finally: 892 # cputimes = os.times() ################### 893 # print "CHANGES:", (cputimes[0] + cputimes[1] - cputime_init), ", count nodes:", len(self.node_names) ################### 894
895 - def listedState(self):
896 ''' 897 Returns a extended roscore state. 898 @return: complete roscore state as 899 900 C{(stamp, stamp_local, masteruri, name, publishers, subscribers, services, topicTypes, nodes, serviceProvider)} 901 902 - C{publishers} is of the form 903 904 C{[ [topic1, [topic1Publisher1...topic1PublisherN]] ... ]} 905 906 - C{subscribers} is of the form 907 908 C{[ [topic1, [topic1Subscriber1...topic1SubscriberN]] ... ]} 909 910 - C{services} is of the form 911 912 C{[ [service1, [service1Provider1...service1ProviderN]] ... ]} 913 914 - C{topicTypes} is a list of 915 916 C{[ [topicName1, topicType1], ... ]} 917 918 - C{nodes} is a list of (the pid of remote Nodes will not be resolved) 919 920 C{[nodename, XML-RPC URI, origin ROS_MASTER_URI, pid, E{lb} local, remote E{rb}]} 921 922 - C{serviceProvider} is a list of (the type, serviceClass and args of remote Services will not be resolved) 923 924 C{[service, XML-RPC URI, origin ROS_MASTER_URI, type, E{lb} local, remote E{rb}]} 925 926 @rtype: C{(float, 927 float, 928 str, 929 str, 930 [ [str,[str] ] ], 931 [ [str,[str] ] ], 932 [ [str,[str] ] ], 933 [ [str,str] ], 934 [ [str,str,str,int,str] ], 935 [ [str,str,str,str,str] ])} 936 ''' 937 stamp = str(self.timestamp) 938 stamp_local = str(self.timestamp_local) 939 publishers = [] 940 subscribers = [] 941 services = [] 942 topicTypes = [] 943 nodes = [] 944 serviceProvider = [] 945 for name, topic in self.topics.items(): 946 pn = topic.publisherNodes 947 if pn: 948 publishers.append((name, pn)) 949 sn = topic.subscriberNodes 950 if sn: 951 subscribers.append((name, sn)) 952 topicTypes.append((name, topic.type)) 953 for name, service in self.services.items(): 954 services.append((name, service.serviceProvider)) 955 serviceProvider.append((name, service.uri, str(service.masteruri), service.type if not service.type is None else '', 'local' if service.isLocal else 'remote')) 956 for name, node in self.nodes.items(): 957 nodes.append((name, node.uri, str(node.masteruri), node.pid, 'local' if node.isLocal else 'remote')) 958 959 return (stamp, stamp_local, self.masteruri, self.mastername, publishers, subscribers, services, topicTypes, nodes, serviceProvider)
960 961 # def __str__(self): 962 # return str(self.listedState()) 963