summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Fan <afan1@jaguarlandrover.com>2016-02-18 18:58:04 -0800
committerAnson Fan <afan1@jaguarlandrover.com>2016-02-18 18:58:04 -0800
commite1bf772b317663313e32f9580888bf80023ed774 (patch)
tree7f070dd9b44e0b39d2cc5fb4d8576c21b34dd561
parentcb97583d4a105667cc2d2b590f0e6351e94f7d2e (diff)
downloadrvi_core-e1bf772b317663313e32f9580888bf80023ed774.tar.gz
Added in a python class rvi_ws_client that will spawn a blocking app which will register services with websockets and return messages to corresponding callback functions. Details on how to use this are included in the top comment block of the file
-rw-r--r--python/rvi_ws.py141
1 files changed, 141 insertions, 0 deletions
diff --git a/python/rvi_ws.py b/python/rvi_ws.py
new file mode 100644
index 0000000..cb73591
--- /dev/null
+++ b/python/rvi_ws.py
@@ -0,0 +1,141 @@
+#
+# Copyright (C) 2016, Jaguar Land Rover
+#
+# This program is licensed under the terms and conditions of the
+# Mozilla Public License, version 2.0. The full text of the
+# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+#
+# rvi_ws 0.1.0
+#
+# This module is the websocket implementation of for RVI services.
+
+# To use this code you will follow these steps.
+# 1. Import the rvi_ws class using "import rvi_ws"
+# 2. Instantiate a rvi_ws_client class object specifying the bundle_id, debug params, and host
+# ex.
+# rvi_client = rvi_ws.rvi_ws_client(bundle_id = <string bundle name>, host = <string host url>, debug = <True|False>)
+# 3. Create a dictionary of services and their callback functions. The keys of the dictionary should be the string service name
+# name and the value should be the pointer to the callback function.
+# ex.
+# def hello(...):
+# ...
+# def world(...):
+# ...
+#
+# rvi_client.register_services({"hello":hello, "world":world})
+#
+# 4. Register and run the services by invoking the services_run() function in the rvi_ws_client class. This will block all other code
+# execution until the websocket connection closes in which case will return a None value.
+# ex.
+# rvi_client.services_run()
+#
+# Optionally there are a few more utility functions included in the rvi_ws_client class mainly setting properties of the class.
+#
+
+import websocket
+import json
+import threading
+
+try:
+ import thread
+# TODO use Threading instead of _thread in python3
+except ImportError:
+ import _thread as thread
+
+# rvi_ws_client will be in charge of handling all communication via websockets between the service bundle and RVI.
+
+class rvi_ws_client:
+
+ def __init__(self, bundle_id = None, debug = False, host = "ws://localhost:9008"):
+
+ self.DEBUG = debug
+ self.service_bundle_id = bundle_id
+ self.callback_funcs = {}
+ self.host = host
+
+ # set_ws_debug takes in parameter debug_status which is type bool. Will toggle on or off all websocket related debug messages.
+ def set_ws_debug(self):
+
+ if self.DEBUG:
+ websocket.enableTrace(True)
+ else:
+ websocket.enableTrace(False)
+
+ # on_error will print an error if the websocket application encounters any and prints if debug is toggled on
+ def on_error(self,ws, error):
+ pass
+
+ # TODO unregister service for clean close of websocket, for time being will just print out debug
+ def on_close(self,ws):
+ pass
+ # What to do on the open of the application. Note we must register_services for this to do anything.
+ def on_open(self,ws):
+
+ def run(*args):
+
+ payload = {}
+ payload['json-rpc'] = "2.0"
+ payload['id'] = "0"
+ payload['method'] = "register_service"
+
+ for service_name, callback in self.callback_funcs.items():
+ payload['params'] = {"service_name":self.service_bundle_id+"/"+service_name}
+ ws.send(json.dumps(payload))
+
+ opening = threading.Thread(target=run)
+ opening.start()
+
+ # on_message will route the message from the websocket to it's corresponding callback function that registered the service
+ def on_message(self,ws, message):
+
+ message_dict = json.loads(message)
+
+ try:
+ if (message_dict['method'] == 'message') and (message_dict['params']['service_name'][(2+len(self.service_bundle_id)):] in self.callback_funcs):
+ self.callback_funcs[message_dict['params']['service_name'][(2+len(self.service_bundle_id)):]](**message_dict['params']['parameters'])
+ except:
+ pass
+
+
+ # set_host will expect a string parameter that will change the class variable host which will connect to our websocket server
+ def set_host(self,target_host):
+
+ self.host = target_host
+ return True
+
+ # register_services will take in a dictionary of services to register.
+ # The keys of the dictionary will be the service name and the value will be the callback function
+ # will return success on successfully changing the class' callback function dictionary
+ # Please make sure that the service name keys are strings.
+ # For example:
+ # services = {
+ # <service_name>:<callback function>,
+ # <service_name>:<callback function>,
+ # ....
+ # }
+ def register_services(self,services):
+
+ self.callback_funcs = services
+ return True
+ # set_service_bundle expects a string parameter that will change the class variable service_bundle_id as the bundle_id tro register
+ def set_service_bundle(self, service_bundle):
+ self.service_bundle_id = service_bundle
+ return True
+
+ # services_run is a callable function for after everything is set to start the websocket client.
+ # Will block all remaining code until the websocket connection is broken. In which case will return None
+ def services_run(self):
+
+ if self.service_bundle_id == None:
+ raise NameError('No Specified bundle_id')
+
+ self.set_ws_debug()
+
+ ws = websocket.WebSocketApp(self.host,
+ on_message = self.on_message,
+ on_error = self.on_error,
+ on_close = self.on_close)
+ ws.on_open = self.on_open
+
+ return ws.run_forever()
+