concert_client.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # License: BSD
00004 #   https://raw.github.com/robotics-in-concert/rocon_app_manager/concert_client/LICENSE
00005 #
00006 ##############################################################################
00007 # Imports
00008 ##############################################################################
00009 
00010 import roslib
00011 roslib.load_manifest('concert_client')
00012 import rospy
00013 
00014 from rocon_hub_client.hub_client import HubClient
00015 from .concertmaster_discovery import ConcertMasterDiscovery
00016 import concert_msgs.msg as concert_msgs
00017 import concert_msgs.srv as concert_srvs
00018 import appmanager_msgs.srv as appmanager_srvs
00019 import gateway_msgs.msg as gateway_msgs
00020 import gateway_msgs.srv as gateway_srvs
00021 from .util import createRule, createRemoteRule
00022 
00023 ##############################################################################
00024 # Concert Client
00025 ##############################################################################
00026 
00027 
00028 class ConcertClient(object):
00029     concertmaster_key = "concertmasterlist"
00030 
00031     hub_client = None
00032 
00033     gateway = None
00034     gateway_srv = {}
00035 
00036     concertmasterlist = []
00037 
00038     invitation_srv = 'invitation'
00039     status_srv = 'status'
00040 
00041     def __init__(self):
00042         ####################
00043         # Variables
00044         ####################
00045         self._is_connected_to_hub = False
00046         self.name = rospy.get_name()
00047         self.param = self._setup_ros_parameters()
00048 
00049         self.hub_client = HubClient(whitelist=self.param['hub_whitelist'],
00050                                     blacklist=self.param['hub_blacklist'],
00051                                     is_zeroconf=False,
00052                                     namespace='rocon',
00053                                     name=self.name,
00054                                     callbacks=None)
00055 
00056         self.masterdiscovery = ConcertMasterDiscovery(self.hub_client, self.concertmaster_key, self.processNewMaster)
00057         self._is_connected_to_concert = False
00058         self._is_connected_to_hub = False
00059 
00060         ####################
00061         # Ros Api Handles
00062         ####################
00063         self.gateway_srv = {}
00064         self.gateway_srv['gateway_info'] = rospy.ServiceProxy('~gateway_info', gateway_srvs.GatewayInfo)
00065         self.gateway_srv['flip'] = rospy.ServiceProxy('~flip', gateway_srvs.Remote)
00066         try:
00067             self.gateway_srv['gateway_info'].wait_for_service()
00068             self.gateway_srv['flip'].wait_for_service()
00069         except rospy.exceptions.ROSInterruptException:
00070             rospy.logerr("Concert Client : interrupted while waiting for gateway services to appear.")
00071             return
00072 
00073         self.appmanager_srv = {}
00074         self.appmanager_srv['init'] = rospy.ServiceProxy('~init', appmanager_srvs.Init)
00075         self.appmanager_srv['init'].wait_for_service()
00076         self.appmanager_srv['apiflip_request'] = rospy.ServiceProxy('~apiflip_request', appmanager_srvs.FlipRequest)
00077         self.appmanager_srv['invitation'] = rospy.ServiceProxy('~relay_invitation', concert_srvs.Invitation)
00078 
00079     def spin(self):
00080         self.connectToHub()
00081         rospy.loginfo("Concert Client: connected to Hub [%s]" % self.hub_uri)
00082         rospy.loginfo("Concert Client; scanning for concerts...")
00083         self.masterdiscovery.start()
00084         rospy.spin()
00085         self.leaveMasters()
00086 
00087     def connectToHub(self):
00088         while not rospy.is_shutdown() and not self._is_connected_to_hub:
00089             rospy.loginfo("Getting Hub info from gateway...")
00090             gateway_info = self.gateway_srv['gateway_info']()
00091             if gateway_info.connected == True:
00092                 hub_uri = gateway_info.hub_uri
00093                 if self.hub_client.connect(hub_uri):
00094                     self.init(gateway_info.name, hub_uri)
00095             else:
00096                 rospy.loginfo("No hub is available. Try later")
00097             rospy.sleep(1.0)
00098 
00099     def init(self, name, uri):
00100         '''
00101         @param name : the unique gateway name
00102         @type string
00103         @param uri : the hub uri
00104         @type string
00105         '''
00106         self._is_connected_to_hub = True
00107         self.name = name
00108         self.hub_uri = uri
00109 
00110         self.service = {}
00111         self.service['invitation'] = rospy.Service(self.name + '/' + self.invitation_srv, concert_srvs.Invitation, self._process_invitation)
00112         self.service['status'] = rospy.Service(self.name + '/' + self.status_srv, concert_srvs.Status, self._process_status)
00113         self.master_services = ['/' + self.name + '/' + self.invitation_srv, '/' + self.name + '/' + self.status_srv]
00114 
00115         app_init_req = appmanager_srvs.InitRequest(name)
00116         rospy.loginfo("Concert Client : initialising the app manager [%s]" % name)
00117         unused_resp = self.appmanager_srv['init'](app_init_req)
00118 
00119     def _setup_ros_parameters(self):
00120         param = {}
00121         param['hub_whitelist'] = ''
00122         param['hub_blacklist'] = ''
00123         param['cm_whitelist'] = []
00124         param['cm_blacklist'] = []
00125 
00126         return param
00127 
00128     def processNewMaster(self, discovered_masterlist):
00129         # find newly discovered masters
00130         new_masters = [m for m in discovered_masterlist if m not in self.concertmasterlist]
00131         self.concertmasterlist += new_masters
00132 
00133         for master in new_masters:
00134             self.joinMaster(master)
00135 
00136         # cleaning gone masters
00137         self.concertmasterlist = [m for m in self.concertmasterlist and discovered_masterlist]
00138 
00139     def joinMaster(self, master):
00140         self.flips(master, self.master_services, gateway_msgs.ConnectionType.SERVICE, True)
00141 
00142         req = appmanager_srvs.FlipRequestRequest(master, True)
00143         resp = self.appmanager_srv['apiflip_request'](req)
00144         if resp.result == False:
00145             rospy.logerr("Concert Client : failed to flip appmanager APIs")
00146 
00147     def leaveMasters(self):
00148         self.masterdiscovery.set_stop()
00149         try:
00150             for master in self.concertmasterlist:
00151                 self._leave_master(master)
00152         except Exception as unused_e:
00153             rospy.logdebug("Concert Client: gateway already down, no shutdown work required.")
00154 
00155     def _leave_master(self, master):
00156         self.flips(master, self.master_services, gateway_msgs.ConnectionType.SERVICE, False)
00157         req = appmanager_srvs.FlipRequestRequest(master, False)
00158         resp = self.appmanager_srv['apiflip_request'](req)
00159         if resp.result == False:
00160             self.logerr("Failed to Flip Appmanager APIs")
00161 
00162     def _process_invitation(self, req):
00163         cm_name = req.name
00164 
00165         # Check if concert master is in white list
00166         if cm_name in self.param['cm_whitelist']:
00167             return self.acceptInvitation(req)
00168         elif len(self.param['cm_whitelist']) == 0 and cm_name not in self.param['cm_blacklist']:
00169             return self.acceptInvitation(req)
00170         else:
00171             return concert_srvs.InvitationResponse(False)
00172 
00173     def acceptInvitation(self, req):
00174         rospy.loginfo("Concert Client : accepting invitation from %s" % req.name)
00175         resp = self.appmanager_srv['invitation'](req)
00176         self._is_connected_to_concert = resp.success
00177         return resp
00178 
00179     def _process_status(self, req):
00180         resp = concert_srvs.StatusResponse()
00181         resp.status = "free-agent" if not self._is_connected_to_concert else "busy"
00182         resp.client_status = concert_msgs.Constants.CONCERT_CLIENT_STATUS_AVAILABLE \
00183                         if not self._is_connected_to_concert else concert_msgs.Constants.CONCERT_CLIENT_STATUS_CONCERT
00184         resp.app_status = concert_msgs.Constants.APP_STATUS_STOPPED  # This is just a stub for now https://github.com/robotics-in-concert/rocon_app_platform/issues/20
00185         return resp
00186 
00187     def flips(self, remote_name, topics, type, ok_flag):
00188         if len(topics) == 0:
00189             return
00190         req = gateway_srvs.RemoteRequest()
00191         req.cancel = not ok_flag
00192         req.remotes = []
00193         for t in topics:
00194             req.remotes.append(createRemoteRule(remote_name, createRule(t, type)))
00195 
00196         resp = self.gateway_srv['flip'](req)
00197 
00198         if resp.result == 0:
00199             rospy.loginfo("Concert Client : successfully flipped to the concert %s" % str(topics))
00200         else:
00201             rospy.logerr("Concert Client : failed to flip [%s][%s]" % (str(topics), str(resp.error_message)))
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends


concert_client
Author(s): Jihoon
autogenerated on Tue Jan 22 2013 12:59:50