summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak Kodihalli <dkodihal@in.ibm.com>2017-10-13 06:40:26 -0500
committerDeepak Kodihalli <dkodihal@in.ibm.com>2017-10-18 07:13:56 -0500
commit639b502e29e7be86a45c3a66fb29d4bcf7b0c793 (patch)
tree858feeead53de61b6ae2a3cf2b1df552d75411da
parentb209dd16eaa495ae3a9fa0fa2e7610fed3c32277 (diff)
downloadphosphor-rest-server-639b502e29e7be86a45c3a66fb29d4bcf7b0c793.tar.gz
phosphor-rest-server-639b502e29e7be86a45c3a66fb29d4bcf7b0c793.zip
rest_dbus: implement client subscription API
Import gobject for running the d-bus event loop, and gevent for a greenlets support. Resolves openbmc/openbmc#2318. Change-Id: Ieaf2e6badcc22159f7470e3fdf949b358fc3e3fe Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
-rw-r--r--module/obmc/wsgi/apps/rest_dbus.py89
1 files changed, 88 insertions, 1 deletions
diff --git a/module/obmc/wsgi/apps/rest_dbus.py b/module/obmc/wsgi/apps/rest_dbus.py
index 1ad359c..323e7da 100644
--- a/module/obmc/wsgi/apps/rest_dbus.py
+++ b/module/obmc/wsgi/apps/rest_dbus.py
@@ -29,6 +29,16 @@ import grp
import crypt
import tempfile
import re
+have_wsock = True
+try:
+ from geventwebsocket import WebSocketError
+except ImportError:
+ have_wsock = False
+if have_wsock:
+ from dbus.mainloop.glib import DBusGMainLoop
+ DBusGMainLoop(set_as_default=True)
+ import gobject
+ import gevent
DBUS_UNKNOWN_INTERFACE = 'org.freedesktop.UnknownInterface'
DBUS_UNKNOWN_INTERFACE_ERROR = 'org.freedesktop.DBus.Error.UnknownInterface'
@@ -719,6 +729,81 @@ class ImagePostHandler(RouteHandler):
pass
+class EventNotifier:
+ keyNames = {}
+ keyNames['event'] = 'event'
+ keyNames['path'] = 'path'
+ keyNames['intfMap'] = 'interfaces'
+ keyNames['propMap'] = 'properties'
+ keyNames['intf'] = 'interface'
+
+ def __init__(self, wsock, filters):
+ self.wsock = wsock
+ self.paths = filters.get("paths", [])
+ self.interfaces = filters.get("interfaces", [])
+ if not self.paths:
+ self.paths.append(None)
+ bus = dbus.SystemBus()
+ # Add a signal receiver for every path the client is interested in
+ for path in self.paths:
+ bus.add_signal_receiver(
+ self.interfaces_added_handler,
+ dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
+ signal_name='InterfacesAdded',
+ path=path)
+ bus.add_signal_receiver(
+ self.properties_changed_handler,
+ dbus_interface=dbus.PROPERTIES_IFACE,
+ signal_name='PropertiesChanged',
+ path=path,
+ path_keyword='path')
+ loop = gobject.MainLoop()
+ # gobject's mainloop.run() will block the entire process, so the gevent
+ # scheduler and hence greenlets won't execute. The while-loop below
+ # works around this limitation by using gevent's sleep, instead of
+ # calling loop.run()
+ gcontext = loop.get_context()
+ while loop is not None:
+ try:
+ if gcontext.pending():
+ gcontext.iteration()
+ else:
+ # gevent.sleep puts only the current greenlet to sleep,
+ # not the entire process.
+ gevent.sleep(5)
+ except WebSocketError:
+ break
+
+ def interfaces_added_handler(self, path, iprops, **kw):
+ ''' If the client is interested in these changes, respond to the
+ client. This handles d-bus interface additions.'''
+ if (not self.interfaces) or \
+ (not set(iprops).isdisjoint(self.interfaces)):
+ response = {}
+ response[self.keyNames['event']] = "InterfacesAdded"
+ response[self.keyNames['path']] = path
+ response[self.keyNames['intfMap']] = iprops
+ try:
+ self.wsock.send(json.dumps(response))
+ except WebSocketError:
+ return
+
+ def properties_changed_handler(self, interface, new, old, **kw):
+ ''' If the client is interested in these changes, respond to the
+ client. This handles d-bus property changes. '''
+ if (not self.interfaces) or (interface in self.interfaces):
+ path = str(kw['path'])
+ response = {}
+ response[self.keyNames['event']] = "PropertiesChanged"
+ response[self.keyNames['path']] = path
+ response[self.keyNames['intf']] = interface
+ response[self.keyNames['propMap']] = new
+ try:
+ self.wsock.send(json.dumps(response))
+ except WebSocketError:
+ return
+
+
class EventHandler(RouteHandler):
''' Handles the /subscribe route, for clients to be able
to subscribe to BMC events. '''
@@ -740,7 +825,9 @@ class EventHandler(RouteHandler):
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
- wsock.send("Connected")
+ filters = wsock.receive()
+ filters = json.loads(filters)
+ notifier = EventNotifier(wsock, filters)
class ImagePutHandler(RouteHandler):
OpenPOWER on IntegriCloud