Commit 30e4803c authored by echel0n's avatar echel0n
Browse files

Misc improvements made to websockets code

parent 5ddb5de2
# Changelog
- * b9f9a48 - 2018-08-24: Pre-Release v9.3.59.dev1
- * eee4815 - 2018-08-24: Misc improvements made to websockets code
- * 5ddb5de - 2018-08-24: Pre-Release v9.3.59.dev1
- * c0b6be8 - 2018-08-24: Added websockets support for ui messages
- * 096b055 - 2018-08-24: Improvements made to tornado web handler code
- * a7f3541 - 2018-08-23: Release v9.3.58
......
......@@ -21,6 +21,7 @@ from __future__ import unicode_literals
import datetime
import sickrage
from sickrage.core.websocket import WebSocketMessage
MESSAGE = 'notice'
ERROR = 'error'
......@@ -43,7 +44,9 @@ class Notifications(object):
message: The message portion of the notification
"""
self._messages.append(Notification(title, message, MESSAGE))
n = Notification(title, message, MESSAGE)
if not WebSocketMessage('notification', n.data).push():
self._messages.append(n)
def error(self, title, message=""):
"""
......@@ -53,7 +56,9 @@ class Notifications(object):
message: The message portion of the notification
"""
self._errors.append(Notification(title, message, ERROR))
n = Notification(title, message, ERROR)
if not WebSocketMessage('notification', n.data).push():
self._errors.append(n)
def get_notifications(self, remote_ip='127.0.0.1'):
"""
......@@ -86,9 +91,17 @@ class Notification(object):
self._when = datetime.datetime.now()
self._seen = []
self.type = type or MESSAGE
self._type = type or MESSAGE
self._timeout = timeout or datetime.timedelta(minutes=1)
@property
def data(self):
return {
'title': self.title,
'body': self.message,
'type': self._type
}
def is_new(self, remote_ip='127.0.0.1'):
"""
Returns True if the notification hasn't been displayed to the current client (aka IP address).
......
......@@ -31,7 +31,8 @@ import sickrage
from sickrage.core.helpers import create_https_certificates, launch_browser
from sickrage.core.webserver.api import ApiHandler, KeyHandler
from sickrage.core.webserver.routes import Route
from sickrage.core.webserver.views import CalendarHandler, LoginHandler, LogoutHandler, WebSocketUIHandler
from sickrage.core.webserver.views import CalendarHandler, LoginHandler, LogoutHandler
from sickrage.core.websocket import WebSocketUIHandler
class StaticImageHandler(StaticFileHandler):
......
......@@ -41,7 +41,6 @@ from tornado.escape import json_encode, recursive_unicode, json_decode
from tornado.gen import coroutine
from tornado.process import cpu_count
from tornado.web import RequestHandler, authenticated
from tornado.websocket import WebSocketHandler, WebSocketClosedError
import sickrage
import sickrage.subtitles
......@@ -297,43 +296,6 @@ class LogoutHandler(BaseHandler):
self.clear_all_cookies()
return self.redirect('/login/')
class WebSocketUIHandler(WebSocketHandler):
"""WebSocket handler to send and receive data to and from a web client."""
clients = set()
def check_origin(self, origin):
"""Allow alternate origins."""
return True
def open(self, *args, **kwargs):
"""Client connected to the WebSocket."""
self.clients.add(self)
# If we have pending messages send them to the new client
for cur_notification in sickrage.app.alerts.get_notifications(self.request.remote_ip):
try:
self.write_message(json_encode({'event': 'notification',
'data': {'title': cur_notification.title,
'message': cur_notification.message,
'type': cur_notification.type}}))
except WebSocketClosedError:
pass
def on_message(self, message):
"""Received a message from the client."""
sickrage.app.log.debug('WebSocket received message from {}: {}'.format(self.request.remote_ip, message))
def on_close(self):
"""Client disconnected from the WebSocket."""
self.clients.remove(self)
def __repr__(self):
"""Client representation."""
return '<{} Client: {}>'.format(type(self).__name__, self.request.remote_ip)
class CalendarHandler(BaseHandler):
def prepare(self, *args, **kwargs):
if sickrage.app.config.calendar_unprotected:
......
import json
from tornado.websocket import WebSocketHandler
import sickrage
clients = set()
class WebSocketUIHandler(WebSocketHandler):
"""WebSocket handler to send and receive data to and from a web client."""
def check_origin(self, origin):
"""Allow alternate origins."""
return True
def open(self, *args, **kwargs):
"""Client connected to the WebSocket."""
clients.add(self)
for n in sickrage.app.alerts.get_notifications(self.request.remote_ip):
self.write_message(n)
def on_message(self, message):
"""Received a message from the client."""
sickrage.app.log.debug('WebSocket received message from {}: {}'.format(self.request.remote_ip, message))
def data_received(self, chunk):
"""Received a streamed data chunk from the client."""
super(WebSocketUIHandler, self).data_received(chunk)
def on_close(self):
"""Client disconnected from the WebSocket."""
clients.remove(self)
def __repr__(self):
"""Client representation."""
return '<{} Client: {}>'.format(type(self).__name__, self.request.remote_ip)
class WebSocketMessage(object):
"""Represents a WebSocket message."""
def __init__(self, event, data):
"""
Construct a new WebSocket message.
:param event: A string representing the type of message (e.g. notification)
:param data: A JSON-serializable object containing the message data.
"""
self.event = event
self.data = data
@property
def content(self):
"""Get the message content."""
return {
'event': self.event,
'data': self.data
}
def push(self):
"""Push the message to all connected WebSocket clients."""
if not clients:
return
msg = json.dumps(self.content)
for client in clients:
sickrage.app.io_loop.add_callback(client.write_message, msg)
......@@ -41,7 +41,7 @@ $(document).ready(function ($) {
// Add handling for different kinds of events. For ex: {"event": "notification", "data": {"title": ..}}
if (msg.event === 'notification') {
SICKRAGE.notify(msg.data.type, msg.data.title, msg.data.message);
SICKRAGE.notify(msg.data.type, msg.data.title, msg.data.body);
}
};
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment