Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
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
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
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
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
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
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
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
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)))