Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BSON Encoding for Binary Objects #190

Merged
merged 6 commits into from
Jul 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rosbridge_library/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<build_depend>python-imaging</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>python-bson</build_depend>

<run_depend>rospy</run_depend>
<run_depend>roscpp</run_depend>
Expand All @@ -35,6 +36,7 @@
<run_depend>python-imaging</run_depend>
<run_depend>geometry_msgs</run_depend>
<run_depend>message_runtime</run_depend>
<run_depend>python-bson</run_depend>

<test_depend>actionlib_msgs</test_depend>
<test_depend>diagnostic_msgs</test_depend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import re
import string
from base64 import standard_b64encode, standard_b64decode
import bson

type_map = {
"bool": ["bool"],
Expand All @@ -64,6 +65,20 @@
ros_binary_types_list_braces = [("uint8[]", re.compile(r'uint8\[[^\]]*\]')),
("char[]", re.compile(r'char\[[^\]]*\]'))]

binary_encoder = None

def get_encoder():
global binary_encoder
if binary_encoder is None:
binary_encoder_type = rospy.get_param('~binary_encoder', 'b64')
if binary_encoder_type == 'b64':
binary_encoder = standard_b64encode
elif binary_encoder_type == 'bson':
binary_encoder = bson.Binary
else:
print "Unknown encoder type '%s'"%binary_encoder_type
exit(0)
return binary_encoder

class InvalidMessageException(Exception):
def __init__(self, inst):
Expand Down Expand Up @@ -97,10 +112,10 @@ def populate_instance(msg, inst):


def _from_inst(inst, rostype):
# Special case for uint8[], we base64 encode the string
# Special case for uint8[], we encode the string
for binary_type, expression in ros_binary_types_list_braces:
if expression.sub(binary_type, rostype) in ros_binary_types:
return standard_b64encode(inst)
return get_encoder()(inst)

# Check for time or duration
if rostype in ros_time_types:
Expand Down
16 changes: 14 additions & 2 deletions rosbridge_library/src/rosbridge_library/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

import rospy
import time

import bson
from rosbridge_library.internal.exceptions import InvalidArgumentException
from rosbridge_library.internal.exceptions import MissingArgumentException

Expand All @@ -47,6 +47,15 @@ def is_number(s):
return True
except ValueError:
return False

def has_binary(d):
if type(d)==bson.Binary:
return True
if type(d)==dict:
for k,v in d.iteritems():
if has_binary(v):
return True
return False

class Protocol:
""" The interface for a single client to interact with ROS.
Expand Down Expand Up @@ -260,7 +269,10 @@ def serialize(self, msg, cid=None):
Returns a JSON string representing the dictionary
"""
try:
return json.dumps(msg)
if has_binary(msg):
return bson.BSON.encode(msg)
else:
return json.dumps(msg)
except:
if cid is not None:
# Only bother sending the log message if there's an id
Expand Down
5 changes: 3 additions & 2 deletions rosbridge_server/src/rosbridge_server/websocket_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

from rosbridge_library.rosbridge_protocol import RosbridgeProtocol
from rosbridge_library.util import json

import bson

class RosbridgeWebSocket(WebSocketHandler):
client_id_seed = 0
Expand Down Expand Up @@ -97,7 +97,8 @@ def on_close(self):
rospy.loginfo("Client disconnected. %d clients total.", cls.clients_connected)

def send_message(self, message):
IOLoop.instance().add_callback(partial(self.write_message, message))
binary = type(message)==bson.BSON
IOLoop.instance().add_callback(partial(self.write_message, message, binary))

def check_origin(self, origin):
return True