summaryrefslogtreecommitdiffstats
path: root/module/remote/wsbackend
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2012-10-13 21:39:58 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2012-10-13 21:39:58 +0200
commit7e7adc64713f74976d5994af36b5f758620fb37b (patch)
tree868084317f8818dbb327c76eaff3c7c7edce0231 /module/remote/wsbackend
parentfixed JsEngine init (diff)
downloadpyload-7e7adc64713f74976d5994af36b5f758620fb37b.tar.xz
added JSON and WS client, re organized tests, new classes for easier api tests
Diffstat (limited to 'module/remote/wsbackend')
-rw-r--r--module/remote/wsbackend/AbstractHandler.py29
-rw-r--r--module/remote/wsbackend/ApiHandler.py22
-rw-r--r--module/remote/wsbackend/AsyncHandler.py112
-rw-r--r--module/remote/wsbackend/EventHandler.py41
4 files changed, 143 insertions, 61 deletions
diff --git a/module/remote/wsbackend/AbstractHandler.py b/module/remote/wsbackend/AbstractHandler.py
index 291dbf100..276f6fa38 100644
--- a/module/remote/wsbackend/AbstractHandler.py
+++ b/module/remote/wsbackend/AbstractHandler.py
@@ -25,10 +25,18 @@ class AbstractHandler:
"""
Abstract Handler providing common methods shared across WebSocket handlers
"""
+ PATH = "/"
+
+ OK = 200
+ UNAUTHORIZED = 401
+ FORBIDDEN = 403
+ NOT_FOUND = 404
+ ERROR = 500
def __init__(self, api):
self.log = get_class_logger()
self.api = api
+ self.core = api.core
def do_extra_handshake(self, req):
self.log.debug("WS Connected: %s" % req)
@@ -58,22 +66,23 @@ class AbstractHandler:
o = loads(msg)
except ValueError, e: #invalid json object
self.log.debug("Invalid Request: %s" % e)
+ self.send_result(req, self.ERROR, "No JSON request")
return None, None, None
- if type(o) != list and len(o) > 2:
+ if type(o) != list and len(o) not in range(1,4):
self.log.debug("Invalid Api call: %s" % o)
- self.send_result(req, 500, "Invalid Api call")
+ self.send_result(req, self.ERROR, "Invalid Api call")
return None, None, None
if len(o) == 1: # arguments omitted
- o.append([])
-
- func, args = o
- if type(args) == list:
- kwargs = {}
+ return o[0], [], {}
+ elif len(o) == 2:
+ func, args = o
+ if type(args) == list:
+ return func, args, {}
+ else:
+ return func, [], args
else:
- args, kwargs = [], args
-
- return func, args, kwargs
+ return tuple(o)
def send_result(self, req, code, result):
return send_message(req, dumps([code, result])) \ No newline at end of file
diff --git a/module/remote/wsbackend/ApiHandler.py b/module/remote/wsbackend/ApiHandler.py
index 57d9ecd5b..e8ba80982 100644
--- a/module/remote/wsbackend/ApiHandler.py
+++ b/module/remote/wsbackend/ApiHandler.py
@@ -34,14 +34,15 @@ class ApiHandler(AbstractHandler):
Non json request will be ignored.
"""
+ PATH = "/api"
+
def transfer_data(self, req):
while True:
try:
line = receive_message(req)
except TypeError, e: # connection closed
self.log.debug("WS Error: %s" % e)
- self.passive_closing_handshake(req)
- return
+ return self.passive_closing_handshake(req)
self.handle_message(line, req)
@@ -55,30 +56,31 @@ class ApiHandler(AbstractHandler):
user = self.api.checkAuth(*args, **kwargs)
if user:
req.api = self.api.withUserContext(user.uid)
- return self.send_result(req, 200, True)
+ return self.send_result(req, self.OK, True)
else:
- return self.send_result(req, 403, "Forbidden")
+ return self.send_result(req, self.FORBIDDEN, "Forbidden")
elif func == 'logout':
req.api = None
- return self.send_result(req, 200, True)
+ return self.send_result(req, self.OK, True)
else:
if not req.api:
- return self.send_result(req, 403, "Forbidden")
+ return self.send_result(req, self.FORBIDDEN, "Forbidden")
if not self.api.isAuthorized(func, req.api.user):
- return self.send_result(req, 401, "Unauthorized")
+ return self.send_result(req, self.UNAUTHORIZED, "Unauthorized")
try:
result = getattr(req.api, func)(*args, **kwargs)
except AttributeError:
- return self.send_result(req, 404, "Not Found")
+ return self.send_result(req, self.NOT_FOUND, "Not Found")
except Exception, e:
- return self.send_result(req, 500, str(e))
+ self.core.print_exc()
+ return self.send_result(req, self.ERROR, str(e))
# None is invalid json type
if result is None: result = True
- return self.send_result(req, 200, result) \ No newline at end of file
+ return self.send_result(req, self.OK, result) \ No newline at end of file
diff --git a/module/remote/wsbackend/AsyncHandler.py b/module/remote/wsbackend/AsyncHandler.py
new file mode 100644
index 000000000..a8382a211
--- /dev/null
+++ b/module/remote/wsbackend/AsyncHandler.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+###############################################################################
+# Copyright(c) 2008-2012 pyLoad Team
+# http://www.pyload.org
+#
+# This file is part of pyLoad.
+# pyLoad is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Subjected to the terms and conditions in LICENSE
+#
+# @author: RaNaN
+###############################################################################
+
+from Queue import Queue
+from threading import Lock
+
+from mod_pywebsocket.msgutil import receive_message
+
+from module.utils import lock
+from AbstractHandler import AbstractHandler
+
+class Mode:
+ STANDBY = 1
+ RUNNING = 2
+
+class AsyncHandler(AbstractHandler):
+ """
+ Handler that provides asynchronous information about server status, running downloads, occurred events.
+
+ Progress information are continuous and will be pushed in a fixed interval when available.
+ After connect you have to login and can set the interval by sending the json command ["setInterval", xy].
+ To start receiving updates call "start", afterwards no more incoming messages will be accept!
+ """
+
+ PATH = "/async"
+ COMMAND = "start"
+
+ PROGRESS_INTERVAL = 1
+ STATUS_INTERVAL = 60
+
+ def __init__(self, api):
+ AbstractHandler.__init__(self, api)
+ self.clients = []
+ self.lock = Lock()
+
+ @lock
+ def on_open(self, req):
+ req.queue = Queue()
+ req.interval = self.PROGRESS_INTERVAL
+ req.mode = Mode.STANDBY
+ self.clients.append(req)
+
+ @lock
+ def on_close(self, req):
+ self.clients.remove(req)
+
+ @lock
+ def add_event(self, event):
+ for req in self.clients:
+ req.queue.put(event)
+
+ def transfer_data(self, req):
+ while True:
+
+ if req.mode == Mode.STANDBY:
+ try:
+ line = receive_message(req)
+ except TypeError, e: # connection closed
+ self.log.debug("WS Error: %s" % e)
+ return self.passive_closing_handshake(req)
+
+ self.mode_standby(line, req)
+ else:
+ if self.mode_running(req):
+ return self.passive_closing_handshake(req)
+
+ def mode_standby(self, msg, req):
+ """ accepts calls before pushing updates """
+ func, args, kwargs = self.handle_call(msg, req)
+ if not func:
+ return # Result was already sent
+
+ if func == 'login':
+ user = self.api.checkAuth(*args, **kwargs)
+ if user:
+ req.api = self.api.withUserContext(user.uid)
+ return self.send_result(req, self.OK, True)
+
+ else:
+ return self.send_result(req, self.FORBIDDEN, "Forbidden")
+
+ elif func == 'logout':
+ req.api = None
+ return self.send_result(req, self.OK, True)
+
+ else:
+ if not req.api:
+ return self.send_result(req, self.FORBIDDEN, "Forbidden")
+ if func == "setInterval":
+ req.interval = args[0]
+ elif func == self.COMMAND:
+ req.mode = Mode.RUNNING
+
+
+ def mode_running(self, req):
+ """ Listen for events, closes socket when returning True """
+ self.send_result(req, "update", "test") \ No newline at end of file
diff --git a/module/remote/wsbackend/EventHandler.py b/module/remote/wsbackend/EventHandler.py
deleted file mode 100644
index 2550ff2eb..000000000
--- a/module/remote/wsbackend/EventHandler.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-###############################################################################
-# Copyright(c) 2008-2012 pyLoad Team
-# http://www.pyload.org
-#
-# This file is part of pyLoad.
-# pyLoad is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# Subjected to the terms and conditions in LICENSE
-#
-# @author: RaNaN
-###############################################################################
-
-from threading import Lock
-
-
-from module.utils import lock
-from AbstractHandler import AbstractHandler
-
-class EventHandler(AbstractHandler):
-
- def __init__(self, api):
- AbstractHandler.__init__(self, api)
- self.clients = []
- self.lock = Lock()
-
- @lock
- def on_open(self, req):
- self.clients.append(req)
-
- @lock
- def on_close(self, req):
- self.clients.remove(req)
-
- def handle_message(self, line, req):
- pass \ No newline at end of file