Skip to content
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
1 change: 1 addition & 0 deletions webthing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
from .event import Event
from .property import Property
from .server import MultipleThings, SingleThing, WebThingServer
from .subscriber import Subscriber
from .thing import Thing
from .value import Value
44 changes: 43 additions & 1 deletion webthing/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import tornado.websocket

from .errors import PropertyError
from .subscriber import Subscriber
from .utils import get_addresses, get_ip


Expand Down Expand Up @@ -161,7 +162,7 @@ def get(self):
self.write(json.dumps(descriptions))


class ThingHandler(tornado.websocket.WebSocketHandler):
class ThingHandler(tornado.websocket.WebSocketHandler, Subscriber):
"""Handle a request to /."""

def initialize(self, things, hosts):
Expand Down Expand Up @@ -341,6 +342,47 @@ def check_origin(self, origin):
"""Allow connections from all origins."""
return True

def update_property(self, property_):
"""
Send an update about a Property.

:param property_: Property
"""
message = json.dumps({
'messageType': 'propertyStatus',
'data': {
property_.name: property_.get_value(),
}
})

self.write_message(message)

def update_action(self, action):
"""
Send an update about an Action.

:param action: Action
"""
message = json.dumps({
'messageType': 'actionStatus',
'data': action.as_action_description(),
})

self.write_message(message)

def update_event(self, event):
"""
Send an update about an Event.

:param event: Event
"""
message = json.dumps({
'messageType': 'event',
'data': event.as_event_description(),
})

self.write_message(message)


class PropertiesHandler(BaseHandler):
"""Handle a request to /properties."""
Expand Down
29 changes: 29 additions & 0 deletions webthing/subscriber.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""High-level Subscriber base class implementation."""


class Subscriber:
"""Abstract Subscriber class."""

def update_property(self, property_):
"""
Send an update about a Property.

:param property_: Property
"""
raise NotImplementedError

def update_action(self, action):
"""
Send an update about an Action.

:param action: Action
"""
raise NotImplementedError

def update_event(self, event):
"""
Send an update about an Event.

:param event: Event
"""
raise NotImplementedError
74 changes: 23 additions & 51 deletions webthing/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from jsonschema import validate
from jsonschema.exceptions import ValidationError
import json
import tornado.websocket


class Thing:
Expand Down Expand Up @@ -391,99 +389,73 @@ def add_available_action(self, name, metadata, cls):
}
self.actions[name] = []

def add_subscriber(self, ws):
def add_subscriber(self, subscriber):
"""
Add a new websocket subscriber.

ws -- the websocket
:param subscriber: Subscriber
"""
self.subscribers.add(ws)
self.subscribers.add(subscriber)

def remove_subscriber(self, ws):
def remove_subscriber(self, subscriber):
"""
Remove a websocket subscriber.

ws -- the websocket
:param subscriber: Subscriber
"""
if ws in self.subscribers:
self.subscribers.remove(ws)
if subscriber in self.subscribers:
self.subscribers.remove(subscriber)

for name in self.available_events:
self.remove_event_subscriber(name, ws)
self.remove_event_subscriber(name, subscriber)

def add_event_subscriber(self, name, ws):
def add_event_subscriber(self, name, subscriber):
"""
Add a new websocket subscriber to an event.

name -- name of the event
ws -- the websocket
:param name: Name of the event
:param subscriber: Subscriber
"""
if name in self.available_events:
self.available_events[name]['subscribers'].add(ws)
self.available_events[name]['subscribers'].add(subscriber)

def remove_event_subscriber(self, name, ws):
def remove_event_subscriber(self, name, subscriber):
"""
Remove a websocket subscriber from an event.

name -- name of the event
ws -- the websocket
:param name: Name of the event
:param subscriber: Subscriber
"""
if name in self.available_events and \
ws in self.available_events[name]['subscribers']:
self.available_events[name]['subscribers'].remove(ws)
subscriber in self.available_events[name]['subscribers']:
self.available_events[name]['subscribers'].remove(subscriber)

def property_notify(self, property_):
"""
Notify all subscribers of a property change.

property_ -- the property that changed
:param property_: the property that changed
"""
message = json.dumps({
'messageType': 'propertyStatus',
'data': {
property_.name: property_.get_value(),
}
})

for subscriber in list(self.subscribers):
try:
subscriber.write_message(message)
except tornado.websocket.WebSocketClosedError:
pass
subscriber.update_property(property_)

def action_notify(self, action):
"""
Notify all subscribers of an action status change.

action -- the action whose status changed
:param action: The action whose status changed
"""
message = json.dumps({
'messageType': 'actionStatus',
'data': action.as_action_description(),
})

for subscriber in list(self.subscribers):
try:
subscriber.write_message(message)
except tornado.websocket.WebSocketClosedError:
pass
subscriber.update_action(action)

def event_notify(self, event):
"""
Notify all subscribers of an event.

event -- the event that occurred
:param event: The event that occurred
"""
if event.name not in self.available_events:
return

message = json.dumps({
'messageType': 'event',
'data': event.as_event_description(),
})

for subscriber in self.available_events[event.name]['subscribers']:
try:
subscriber.write_message(message)
except tornado.websocket.WebSocketClosedError:
pass
subscriber.update_event(event)