00001 from rosbridge_library.internal.ros_loader import get_service_class
00002 from rosbridge_library.internal import message_conversion
00003
00004 from rosbridge_library.capability import Capability
00005 import rospy
00006 from datetime import datetime
00007 import time
00008 import threading
00009
00010
00011
00012 class ServiceList():
00013 """
00014 Singleton class to hold lists of registered services in one 'global' object
00015 """
00016 class __impl:
00017 """ Implementation of the singleton interface """
00018 def spam(self):
00019 """ Test method, return singleton id """
00020 return id(self)
00021
00022 __instance = None
00023 list = {}
00024
00025 def __init__(self):
00026 """ Create singleton instance """
00027 if ServiceList.__instance is None:
00028 ServiceList.__instance = ServiceList.__impl()
00029 self.list = {}
00030
00031 self.__dict__['_ServiceList__instance'] = ServiceList.__instance
00032
00033 def __getattr__(self, attr):
00034 """ Delegate access to implementation """
00035 return getattr(self.__instance, attr)
00036
00037 def __setattr__(self, attr, value):
00038 """ Delegate access to implementation """
00039 return setattr(self.__instance, attr, value)
00040
00041 class RequestList():
00042 """
00043 Singleton class to hold lists of received requests in one 'global' object
00044 """
00045 class __impl:
00046 """ Implementation of the singleton interface """
00047 def spam(self):
00048 """ Test method, return singleton id """
00049 return id(self)
00050
00051 __instance = None
00052 list = {}
00053
00054 def __init__(self):
00055 """ Create singleton instance """
00056 if RequestList.__instance is None:
00057 RequestList.__instance = RequestList.__impl()
00058 self.list = {}
00059
00060 self.__dict__['_RequestList__instance'] = RequestList.__instance
00061
00062 def __getattr__(self, attr):
00063 """ Delegate access to implementation """
00064 return getattr(self.__instance, attr)
00065
00066 def __setattr__(self, attr, value):
00067 """ Delegate access to implementation """
00068 return setattr(self.__instance, attr, value)
00069
00070
00071 class ReceivedResponses():
00072 """
00073 Singleton class to hold lists of received service responses in one 'global' object
00074 """
00075 class __impl:
00076 """ Implementation of the singleton interface """
00077 def spam(self):
00078 """ Test method, return singleton id """
00079 return id(self)
00080
00081 __instance = None
00082 list = {}
00083
00084 def __init__(self):
00085 """ Create singleton instance """
00086 if ReceivedResponses.__instance is None:
00087 ReceivedResponses.__instance = ReceivedResponses.__impl()
00088 self.list = {}
00089
00090 self.__dict__['_ReceivedResponses__instance'] = ReceivedResponses.__instance
00091
00092 def __getattr__(self, attr):
00093 """ Delegate access to implementation """
00094 return getattr(self.__instance, attr)
00095
00096 def __setattr__(self, attr, value):
00097 """ Delegate access to implementation """
00098 return setattr(self.__instance, attr, value)
00099
00100
00101
00102 class ROS_Service_Template( threading.Thread):
00103 service_request_timeout = 600
00104 check_response_delay = 0.1
00105 wait_for_busy_service_provider = 0.1
00106
00107 max_requests = 500000
00108
00109 service_name = None
00110 service_node_name = None
00111 service_module = None
00112 service_type = None
00113 client_callback = None
00114
00115 client_id = None
00116 service_id = None
00117
00118 ros_serviceproxy = None
00119
00120 request_counter = 0
00121
00122 response_list = ReceivedResponses().list
00123 protocol = None
00124
00125 finish_flag = False
00126 busy = False
00127 spawned = False
00128
00129 def __init__(self, client_callback, service_module, service_type, service_name, client_id, protocol):
00130 threading.Thread.__init__(self)
00131
00132 self.protocol = protocol
00133 self.service_name = service_name
00134 self.service_module = service_module
00135 self.service_type = service_type
00136 self.client_id = client_id
00137 self.client_callback = client_callback
00138
00139
00140 if self.protocol.parameters != None:
00141 self.service_request_timeout = self.protocol.parameters["service_request_timeout"]
00142 self.check_response_delay = self.protocol.parameters["check_response_delay"]
00143 self.wait_for_busy_service_provider = self.protocol.parameters["wait_for_busy_service_provider"]
00144 self.max_requests = self.protocol.parameters["max_service_requests"]
00145
00146 self.spawn_ROS_service( service_module, service_type, service_name, client_id)
00147
00148
00149 def handle_service_request(self, req):
00150
00151
00152 while not self.spawned or self.busy:
00153
00154 if self.finish_flag:
00155
00156 return None
00157 time.sleep(self.wait_for_busy_service_provider)
00158
00159 self.busy = True
00160
00161
00162
00163 request_id = "service:" + self.service_name + "_count:" + str(self.request_counter) + "_time:" + datetime.now().strftime("%H:%M:%f")
00164
00165 self.request_counter = (self.request_counter + 1) % self.max_requests
00166
00167 req_extracted = message_conversion.extract_values(req)
00168 request_message_object = {"op":"service_request",
00169 "request_id": request_id,
00170 "args": req_extracted
00171 }
00172
00173
00174 if request_id not in self.protocol.request_list.keys():
00175
00176 self.protocol.request_list[request_id] = { "service_name" : self.service_name,
00177 "service_module" : self.service_module,
00178 "service_type" : self.service_type
00179 }
00180
00181 answer = None
00182 try:
00183
00184 self.client_callback( request_message_object )
00185 begin = datetime.now()
00186 duration = datetime.now() - begin
00187
00188
00189 while not self.finish_flag and request_id not in self.response_list.keys() and duration.total_seconds() < self.service_request_timeout:
00190 time.sleep(self.check_response_delay)
00191 duration = datetime.now() - begin
00192
00193 if request_id in self.response_list:
00194 answer = self.response_list[request_id]
00195
00196 del self.response_list[request_id]
00197 else:
00198
00199 print "request timed out!"
00200 answer = None
00201
00202 del self.protocol.request_list[request_id]
00203
00204 except Exception, e:
00205 print e
00206 self.busy = False
00207 return answer
00208
00209 def stop_ROS_service(self):
00210 self.spawned = False
00211 self.finish_flag = True
00212 self.ros_serviceproxy.shutdown("reason: stop_service requested by providing client")
00213
00214
00215 for request_id in self.protocol.request_list.keys():
00216 self.protocol.response_list[request_id] = None
00217
00218 while len(self.protocol.request_list) > 0:
00219 time.sleep(self.check_response_delay)
00220
00221
00222 del self.protocol.service_list[self.service_name]
00223 self.protocol.log("info", "removed service: "+ self.service_name)
00224
00225 def spawn_ROS_service(self, service_module, service_type, service_name, client_id):
00226
00227 service_class = get_service_class(service_module+'/'+service_type)
00228
00229 self.ros_serviceproxy = rospy.Service( service_name, service_class, self.handle_service_request)
00230
00231
00232
00233
00234
00235
00236
00237 log_msg = "registered service: " + self.service_name
00238 self.protocol.log("info", log_msg)
00239 self.spawned = True
00240
00241 class AdvertiseService(Capability):
00242
00243 opcode_advertise_service = "advertise_service"
00244 service_list = ServiceList().list
00245 request_list = RequestList().list
00246
00247 def __init__(self, protocol):
00248 self.protocol = protocol
00249 Capability.__init__(self, protocol)
00250 protocol.register_operation(self.opcode_advertise_service, self.advertise_service)
00251 self.protocol.service_list = self.service_list
00252 self.protocol.request_list = self.request_list
00253
00254 def advertise_service(self, message):
00255 opcode = message["op"]
00256 service_type = message["service_type"]
00257 service_name = message["service_name"]
00258 service_module = message["service_module"]
00259 client_id = self.protocol.client_id
00260 client_callback = self.protocol.send
00261
00262 if service_name not in self.service_list.keys():
00263 self.service_list[service_name] = ROS_Service_Template(client_callback , service_module, service_type, service_name, client_id, self.protocol)
00264 else:
00265 log_msg = "is replacing service: " + service_name + " [provided before by client:" + str(self.service_list[service_name].client_id) + "]"
00266 self.protocol.log("info", log_msg)
00267 self.service_list[service_name].stop_ROS_service()
00268 self.service_list[service_name] = ROS_Service_Template(client_callback , service_module, service_type, service_name, client_id, self.protocol )
00269
00270 def finish(self):
00271 self.finish_flag = True
00272 self.protocol.unregister_operation("advertise_service")