Package concert_conductor :: Module concert_client
[frames] | no frames]

Source Code for Module concert_conductor.concert_client

  1  #!/usr/bin/env python 
  2  # 
  3  # License: BSD 
  4  #   https://raw.github.com/robotics-in-concert/rocon_concert/concert_conductor/LICENSE 
  5  # 
  6  ############################################################################## 
  7  # Imports 
  8  ############################################################################## 
  9   
 10  import rospy 
 11  import rocon_app_manager_msgs.msg as rapp_manager_msgs 
 12  import rocon_app_manager_msgs.srv as rapp_manager_srvs 
 13  import concert_msgs.msg as concert_msgs 
 14  import gateway_msgs.msg as gateway_msgs 
 15  import gateway_msgs.srv as gateway_srvs 
 16   
 17  ############################################################################## 
 18  # Exceptions 
 19  ############################################################################## 
 20   
 21   
22 -class ConcertClientException(Exception):
23 """Exception class for concert client related errors""" 24 pass
25 26 ############################################################################## 27 # ClientInfo Class 28 ############################################################################## 29 30
31 -class ConcertClient(object):
32
33 - def __init__(self, client_name, gateway_name, is_local_client=False):
34 ''' 35 Initialise, finally ending with a call on the service to the client's 36 platform info service. 37 38 @param client_name : a string (+ index) human consumable form of the name 39 @type str 40 @param gateway_name : the name with 16 byte hash attached 41 @type str 42 @param is_local_client : differentiates an interactive local client from a gateway client 43 @type bool 44 45 @raise ConcertClientException : when platform info service is unavailable 46 ''' 47 48 self.data = concert_msgs.ConcertClient() 49 self.gateway_name = gateway_name # this is the rather unsightly name + hash key 50 self.name = client_name # usually name (+ index), a more human consumable name 51 52 self.platform_info = None 53 self.service_execution = {} # Services to execute, e.g. start_app, stop_app 54 self._is_local_client = is_local_client # As opposed to a gateway client 55 if not self._is_local_client: 56 self._pull_concert_client() # get concert client info and pull required handles in 57 # could maybe catch an exception on error here 58 self._init() 59 self._setup_service_proxies() 60 61 try: 62 self._update() 63 except ConcertClientException: 64 raise
65
66 - def _pull_concert_client(self):
67 ''' 68 Pulls platform information from the advertised platform_info on another 69 ros system. It is just a one-shot only used at construction time. 70 71 It pulls platform_info and list_apps information. 72 73 It also pulls the required handles in for further manipulation ('status' and 'invite') 74 ''' 75 rospy.loginfo("Conductor: retrieving client information [%s]" % self.name) 76 pull_service = rospy.ServiceProxy('~pull', gateway_srvs.Remote) 77 req = gateway_srvs.RemoteRequest() 78 req.cancel = False 79 req.remotes = [] 80 for service_name in ['platform_info', 'list_apps', 'status', 'invite']: 81 rule = gateway_msgs.Rule() 82 rule.name = str('/' + self.gateway_name + '/' + service_name) 83 rule.node = '' 84 rule.type = gateway_msgs.ConnectionType.SERVICE 85 req.remotes.append(gateway_msgs.RemoteRule(self.gateway_name.lstrip('/'), rule)) 86 resp = pull_service(req) 87 if resp.result != 0: 88 rospy.logwarn("Conductor: failed to pull the platform info service from the client.") 89 return None
90
91 - def _init(self):
92 # Platform_info 93 platform_info_service = rospy.ServiceProxy(str('/' + self.gateway_name + '/' + 'platform_info'), rapp_manager_srvs.GetPlatformInfo) 94 list_app_service = rospy.ServiceProxy(str('/' + self.gateway_name + '/' + 'list_apps'), rapp_manager_srvs.GetAppList) 95 # These are permanent 96 self._status_service = rospy.ServiceProxy('/' + str(self.gateway_name + '/' + 'status'), rapp_manager_srvs.Status) 97 self._invite_service = rospy.ServiceProxy('/' + str(self.gateway_name + '/' + 'invite'), rapp_manager_srvs.Invite) 98 try: 99 platform_info_service.wait_for_service() 100 list_app_service.wait_for_service() 101 self._status_service.wait_for_service() 102 self._invite_service.wait_for_service() 103 except rospy.ServiceException, e: 104 raise e 105 platform_info = platform_info_service().platform_info 106 self.data.name = platform_info.name 107 self.data.platform = platform_info.platform 108 self.data.system = platform_info.system 109 self.data.robot = platform_info.robot 110 # List Apps 111 try: 112 list_app_service.wait_for_service() 113 except rospy.ServiceException, e: 114 raise e 115 self.data.apps = list_app_service().apps
116
117 - def to_msg_format(self):
118 ''' 119 Returns the updated client information status in ros-consumable msg format. 120 121 @return the client information as a ros message. 122 @rtype concert_msgs.ConcertClient 123 124 @raise rospy.service.ServiceException : when assumed service link is unavailable 125 ''' 126 try: 127 self._update() 128 except ConcertClientException: 129 raise 130 return self.data
131
132 - def _update(self):
133 ''' 134 Adds the current client status to the platform_info, list_apps information already 135 retrieved from the client and puts them in a convenient msg format, 136 ready for exposing outside the conductor (where? I can't remember). 137 138 @raise rospy.service.ServiceException : when assumed service link is unavailable 139 ''' 140 try: 141 status = self._status_service(rapp_manager_srvs.StatusRequest()) 142 except rospy.service.ServiceException: 143 raise ConcertClientException("client platform information services unavailable (disconnected?)") 144 self.data.name = self.name # use the human friendly name 145 self.data.gateway_name = self.gateway_name 146 #self.data.name = status.namespace 147 self.data.last_connection_timestamp = rospy.Time.now() 148 if status.remote_controller == rapp_manager_msgs.Constants.NO_REMOTE_CONNECTION: 149 self.data.client_status = concert_msgs.Constants.CONCERT_CLIENT_STATUS_AVAILABLE 150 # Todo - fix this 151 #elif status.remote_controller == _this_concert_name: 152 # self.data.client_status = concert_msgs.Constants.CONCERT_CLIENT_STATUS_CONNECTED 153 else: 154 self.data.client_status = concert_msgs.Constants.CONCERT_CLIENT_STATUS_CONNECTED
155 # self.data.client_status = concert_msgs.Constants.CONCERT_CLIENT_STATUS_UNAVAILABLE 156
157 - def invite(self, concert_gateway_name, client_local_name, ok_flag):
158 ''' 159 Bit messy with ok_flag here as we are mid-transition to using 'cancel' flag in the 160 invite services. 161 162 @param concert_gateway_name : have to let the client know the concert gateway name 163 so they can flip us topics... 164 @type str 165 ''' 166 req = rapp_manager_srvs.InviteRequest(concert_gateway_name, client_local_name, not ok_flag) 167 resp = self._invite_service(req) 168 169 if resp.result == True: 170 self._setup_service_proxies() 171 else: 172 raise Exception(str("Invitation Failed : " + self.name))
173
174 - def start_app(self, app_name, remappings):
175 ''' 176 @param app_name : string unique identifier for the app 177 @type string 178 @param remappings : list of (from,to) pairs 179 @type list of tuples 180 ''' 181 self._start_app_service.wait_for_service() 182 req = rapp_manager_srvs.StartAppRequest() 183 req.name = app_name 184 req.remappings = [] 185 for remapping in remappings: 186 req.remappings.append(rapp_manager_msgs.Remapping(remapping[0], remapping[1])) 187 unused_resp = self._start_app_service(req)
188
189 - def _setup_service_proxies(self):
190 self._start_app_service = rospy.ServiceProxy(str(self.name + '/start_app'), rapp_manager_srvs.StartApp) 191 self._stop_app_service = rospy.ServiceProxy(str(self.name + '/stop_app'), rapp_manager_srvs.StopApp)
192