52 """ Returns True if obj is a binary or contains a binary attribute 55 if isinstance(obj, list):
58 if isinstance(obj, dict):
59 return any(
has_binary(obj[item])
for item
in obj)
61 return isinstance(obj, bson.binary.Binary)
65 """ The interface for a single client to interact with ROS. 67 See rosbridge_protocol for the default protocol used by rosbridge 69 The lifecycle for a Protocol instance is as follows: 70 - Pass incoming messages from the client to incoming 71 - Propagate outgoing messages to the client by overriding outgoing 72 - Call finish to clean up resources when the client is finished 87 delay_between_messages = 0
89 external_service_list = {}
91 bson_only_mode =
False 96 """ Keyword arguments: 97 client_id -- a unique ID for this client to take. Uniqueness is 98 important otherwise there will be conflicts between multiple clients 114 """ Process an incoming message from the client 117 message_string -- the wire-level message sent by the client 131 except Exception
as e:
137 self.
log(
"error",
"Exception in deserialization of BSON")
152 opening_brackets = [i
for i, letter
in enumerate(self.
buffer)
if letter ==
'{']
153 closing_brackets = [i
for i, letter
in enumerate(self.
buffer)
if letter ==
'}']
155 for start
in opening_brackets:
156 for end
in closing_brackets:
159 if msg.get(
"op",
None) !=
None:
164 except Exception
as e:
181 if "receiver" in msg:
182 self.
log(
"error",
"Received a rosbridge v1.0 message. Please refer to rosbridge.org for the correct format of rosbridge v2.0 messages. Original message was: %s" % message_string)
184 self.
log(
"error",
"Received a message without an op. All messages require 'op' field with value one of: %s. Original message was: %s" % (list(self.operations.keys()), message_string), mid)
188 self.
log(
"error",
"Unknown operation: %s. Allowed operations: %s" % (op, list(self.operations.keys())), mid)
192 if "fragment_size" in msg.keys():
195 if "message_intervall" in msg.keys()
and is_number(msg[
"message_intervall"]):
197 if "png" in msg.keys():
198 self.
png = msg[
"msg"]
203 except Exception
as exc:
204 self.
log(
"error",
"%s: %s" % (op, str(exc)), mid)
217 """ Pass an outgoing message to the client. This method should be 221 message -- the wire-level message to send to the client 226 def send(self, message, cid=None):
227 """ Called internally in preparation for sending messages to the client 229 This method pre-processes the message then passes it to the overridden 233 message -- a dict of message values to be marshalled and sent 234 cid -- (optional) an associated id 237 serialized = self.serialize(message, cid)
238 if serialized
is not None:
239 if self.png ==
"png":
245 if self.fragment_size !=
None and len(serialized) > self.fragment_size:
246 mid = message.get(
"id",
None)
250 fragment_list = Fragmentation(self).
fragment(message, self.fragment_size, mid )
253 if fragment_list !=
None:
254 for fragment
in fragment_list:
255 if self.bson_only_mode:
256 self.outgoing(bson.BSON.encode(fragment))
258 self.outgoing(json.dumps(fragment))
261 time.sleep(self.delay_between_messages)
264 self.outgoing(serialized)
265 time.sleep(self.delay_between_messages)
268 """ Indicate that the client is finished and clean up resources. 270 All clients should call this method after disconnecting. 277 """ Turns a dictionary of values into the appropriate wire-level 280 Default behaviour uses JSON. Override to use a different container. 283 msg -- the dictionary of values to serialize 284 cid -- (optional) an ID associated with this. Will be logged on err. 286 Returns a JSON string representing the dictionary 289 if type(msg) == bytearray:
292 return bson.BSON.encode(msg)
294 return json.dumps(msg)
298 self.
log(
"error",
"Unable to serialize %s message to client" 304 """ Turns the wire-level representation into a dictionary of values 306 Default behaviour assumes JSON. Override to use a different container. 309 msg -- the wire-level message to deserialize 310 cid -- (optional) an ID associated with this. Is logged on error 312 Returns a dictionary of values 317 bson_message = bson.BSON(msg)
318 return bson_message.decode()
320 return json.loads(msg)
321 except Exception
as e:
339 """ Register a handler for an opcode 342 opcode -- the opcode to register this handler for 343 handler -- a callback function to call for messages with this opcode 349 """ Unregister a handler for an opcode 352 opcode -- the opcode to unregister the handler for 359 """ Add a capability to the protocol. 361 This method is for convenience; assumes the default capability 365 capability_class -- the class of the capability to add 368 self.capabilities.append(capability_class(self))
370 def log(self, level, message, lid=None):
371 """ Log a message to the client. By default just sends to stdout 374 level -- the logger level of this message 375 message -- the string message to send to the user 376 lid -- an associated for this log message 379 stdout_formatted_msg =
None 381 stdout_formatted_msg =
"[Client %s] [id: %s] %s" % (self.
client_id, lid, message)
383 stdout_formatted_msg =
"[Client %s] %s" % (self.
client_id, message)
385 if level ==
"error" or level ==
"err":
386 rospy.logerr(stdout_formatted_msg)
387 elif level ==
"warning" or level ==
"warn":
388 rospy.logwarn(stdout_formatted_msg)
389 elif level ==
"info" or level ==
"information":
390 rospy.loginfo(stdout_formatted_msg)
392 rospy.logdebug(stdout_formatted_msg)
def register_operation(self, opcode, handler)
def unregister_operation(self, opcode)
def __init__(self, client_id)
def add_capability(self, capability_class)
def deserialize(self, msg, cid=None)
int delay_between_messages
def outgoing(self, message)
def log(self, level, message, lid=None)
def send(self, message, cid=None)
def incoming(self, message_string="")
def serialize(self, msg, cid=None)