diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2012-10-11 20:55:48 +0200 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2012-10-11 20:55:48 +0200 |
commit | 582b8eb777a86a157f4825e3d9d68e8655e8f092 (patch) | |
tree | 2c96b04e167135101c57d2ef2d387380f60c1370 /module/remote | |
parent | last test commit (diff) | |
download | pyload-582b8eb777a86a157f4825e3d9d68e8655e8f092.tar.xz |
refactored ws handler, generate debug information for ttypes
Diffstat (limited to 'module/remote')
-rw-r--r-- | module/remote/create_ttypes.py | 72 | ||||
-rw-r--r-- | module/remote/ttypes_debug.py | 277 | ||||
-rw-r--r-- | module/remote/wsbackend/AbstractHandler.py | 79 | ||||
-rw-r--r-- | module/remote/wsbackend/ApiHandler.py | 50 | ||||
-rw-r--r-- | module/remote/wsbackend/EventHandler.py | 32 |
5 files changed, 451 insertions, 59 deletions
diff --git a/module/remote/create_ttypes.py b/module/remote/create_ttypes.py index a9a93bde7..023db60bb 100644 --- a/module/remote/create_ttypes.py +++ b/module/remote/create_ttypes.py @@ -11,9 +11,44 @@ module = join(path, "..", "..") sys.path.append(join(module, "lib")) sys.path.append(join(module, "remote")) +from thrift.Thrift import TType from thriftgen.pyload import ttypes -from thriftgen.pyload.Pyload import Iface +from thriftgen.pyload import Pyload + +type_map = { + TType.BOOL: 'bool', + TType.DOUBLE: 'float', + TType.I16: 'int', + TType.I32: 'int', + TType.I64: 'int', + TType.STRING: 'basestring', + TType.MAP: 'dict', + TType.LIST: 'list', + TType.SET: 'set', + TType.VOID: 'None', + TType.STRUCT: 'BaseObject', + TType.UTF8: 'unicode', +} + +def write_spec(attr, spec, f): + """ analyze the generated spec file and writes information into file """ + if spec[1] == TType.STRUCT: + f.write("\t'%s': %s,\n" % (attr, spec[3][0].__name__)) + elif spec[1] == TType.LIST: + if spec[3][0] == TType.STRUCT: + ttype = spec[3][1][0].__name__ + else: + ttype = type_map[spec[3][0]] + f.write("\t'%s': (list, %s),\n" % (attr, ttype)) + elif spec[1] == TType.MAP: + if spec[3][2] == TType.STRUCT: + ttype = spec[3][3][0].__name__ + else: + ttype = type_map[spec[3][2]] + f.write("\t'%s': (dict, %s, %s),\n" % (attr, type_map[spec[3][0]], ttype)) + else: + f.write("\t'%s': %s,\n" % (attr, type_map[spec[1]])) def main(): @@ -35,7 +70,6 @@ def main(): f = open(join(path, "ttypes.py"), "wb") - f.write( """#!/usr/bin/env python # -*- coding: utf-8 -*- @@ -47,6 +81,14 @@ class BaseObject(object): """) + dev = open(join(path, "ttypes_debug.py"), "wb") + dev.write("""#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Autogenerated by pyload +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n +from ttypes import *\n +""") + ## generate enums for enum in enums: name = enum.__name__ @@ -59,33 +101,53 @@ class BaseObject(object): f.write("\n") + dev.write("classes = {\n\n") + for klass in classes: name = klass.__name__ base = "Exception" if issubclass(klass, ttypes.TExceptionBase) else "BaseObject" f.write("class %s(%s):\n" % (name, base)) f.write("\t__slots__ = %s\n\n" % klass.__slots__) + dev.write("'%s' : {\n" % name) #create init args = ["self"] + ["%s=None" % x for x in klass.__slots__] f.write("\tdef __init__(%s):\n" % ", ".join(args)) - for attr in klass.__slots__: + for i, attr in enumerate(klass.__slots__): f.write("\t\tself.%s = %s\n" % (attr, attr)) + spec = klass.thrift_spec[i+1] + assert spec[2] == attr + write_spec(attr, spec, dev) + f.write("\n") + dev.write("},\n") + + dev.write("}\n\n") f.write("class Iface(object):\n") + dev.write("methods = {\n") - for name in dir(Iface): + for name in dir(Pyload.Iface): if name.startswith("_"): continue - func = inspect.getargspec(getattr(Iface, name)) + func = inspect.getargspec(getattr(Pyload.Iface, name)) f.write("\tdef %s(%s):\n\t\tpass\n" % (name, ", ".join(func.args))) + spec = getattr(Pyload, "%s_result" % name).thrift_spec + if not spec or not spec[0]: + dev.write("\t'%s': None,\n" % name) + else: + spec = spec[0] + write_spec(name, spec, dev) + f.write("\n") + dev.write("}\n") f.close() + dev.close() if __name__ == "__main__": main()
\ No newline at end of file diff --git a/module/remote/ttypes_debug.py b/module/remote/ttypes_debug.py new file mode 100644 index 000000000..dca54a56a --- /dev/null +++ b/module/remote/ttypes_debug.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Autogenerated by pyload +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +from ttypes import * + +classes = { + +'AccountInfo' : { + 'plugin': basestring, + 'loginname': basestring, + 'owner': int, + 'valid': bool, + 'validuntil': int, + 'trafficleft': int, + 'maxtraffic': int, + 'premium': bool, + 'activated': bool, + 'shared': bool, + 'options': (dict, basestring, basestring), +}, +'AddonInfo' : { + 'func_name': basestring, + 'description': basestring, + 'value': basestring, +}, +'AddonService' : { + 'func_name': basestring, + 'description': basestring, + 'arguments': (list, basestring), + 'media': int, +}, +'ConfigHolder' : { + 'name': basestring, + 'label': basestring, + 'description': basestring, + 'long_description': basestring, + 'items': (list, ConfigItem), + 'info': (list, AddonInfo), + 'handler': (list, InteractionTask), +}, +'ConfigInfo' : { + 'name': basestring, + 'label': basestring, + 'description': basestring, + 'saved': bool, + 'activated': bool, +}, +'ConfigItem' : { + 'name': basestring, + 'label': basestring, + 'description': basestring, + 'type': basestring, + 'default_value': basestring, + 'value': basestring, +}, +'DownloadInfo' : { + 'url': basestring, + 'plugin': basestring, + 'hash': basestring, + 'status': int, + 'statusmsg': basestring, + 'error': basestring, +}, +'DownloadProgress' : { + 'fid': int, + 'pid': int, + 'speed': int, + 'status': int, +}, +'EventInfo' : { + 'eventname': basestring, + 'event_args': (list, basestring), +}, +'FileDoesNotExists' : { + 'fid': int, +}, +'FileInfo' : { + 'fid': int, + 'name': basestring, + 'package': int, + 'owner': int, + 'size': int, + 'status': int, + 'media': int, + 'added': int, + 'fileorder': int, + 'download': DownloadInfo, +}, +'InteractionTask' : { + 'iid': int, + 'input': int, + 'data': (list, basestring), + 'output': int, + 'default_value': basestring, + 'title': basestring, + 'description': basestring, + 'plugin': basestring, +}, +'LinkStatus' : { + 'url': basestring, + 'name': basestring, + 'plugin': basestring, + 'size': int, + 'status': int, + 'packagename': basestring, +}, +'OnlineCheck' : { + 'rid': int, + 'data': (dict, basestring, LinkStatus), +}, +'PackageDoesNotExists' : { + 'pid': int, +}, +'PackageInfo' : { + 'pid': int, + 'name': basestring, + 'folder': basestring, + 'root': int, + 'owner': int, + 'site': basestring, + 'comment': basestring, + 'password': basestring, + 'added': int, + 'tags': (list, basestring), + 'status': int, + 'packageorder': int, + 'stats': PackageStats, + 'fids': (list, int), + 'pids': (list, int), +}, +'PackageStats' : { + 'linkstotal': int, + 'linksdone': int, + 'sizetotal': int, + 'sizedone': int, +}, +'ProgressInfo' : { + 'plugin': basestring, + 'name': basestring, + 'statusmsg': basestring, + 'eta': int, + 'format_eta': basestring, + 'done': int, + 'total': int, + 'download': DownloadProgress, +}, +'ServerStatus' : { + 'pause': bool, + 'active': int, + 'queue': int, + 'total': int, + 'speed': int, + 'download': bool, + 'reconnect': bool, +}, +'ServiceDoesNotExists' : { + 'plugin': basestring, + 'func': basestring, +}, +'ServiceException' : { + 'msg': basestring, +}, +'TreeCollection' : { + 'root': PackageInfo, + 'files': (dict, int, FileInfo), + 'packages': (dict, int, PackageInfo), +}, +'UserData' : { + 'uid': int, + 'name': basestring, + 'email': basestring, + 'role': int, + 'permission': int, + 'folder': basestring, + 'traffic': int, + 'dllimit': int, + 'dlquota': basestring, + 'hddquota': int, + 'user': int, + 'templateName': basestring, +}, +'UserDoesNotExists' : { + 'user': basestring, +}, +} + +methods = { + 'addFromCollector': int, + 'addLinks': None, + 'addLocalFile': None, + 'addPackage': int, + 'addPackageChild': int, + 'addPackageP': int, + 'addToCollector': None, + 'addUser': UserData, + 'callAddon': None, + 'callAddonHandler': None, + 'checkOnlineStatus': OnlineCheck, + 'checkOnlineStatusContainer': OnlineCheck, + 'checkURLs': (dict, basestring, list), + 'configurePlugin': ConfigHolder, + 'createPackage': int, + 'deleteCollLink': None, + 'deleteCollPack': None, + 'deleteConfig': None, + 'deleteFiles': None, + 'deletePackages': None, + 'findFiles': TreeCollection, + 'freeSpace': int, + 'generateAndAddPackages': (list, int), + 'generateDownloadLink': basestring, + 'generatePackages': (dict, basestring, list), + 'getAccountTypes': (list, basestring), + 'getAccounts': (list, AccountInfo), + 'getAddonHandler': (dict, basestring, list), + 'getAllFiles': TreeCollection, + 'getAllInfo': (dict, basestring, list), + 'getAllUserData': (dict, int, UserData), + 'getCollector': (list, LinkStatus), + 'getConfig': (dict, basestring, ConfigHolder), + 'getEvents': (list, EventInfo), + 'getFileInfo': FileInfo, + 'getFileTree': TreeCollection, + 'getFilteredFileTree': TreeCollection, + 'getFilteredFiles': TreeCollection, + 'getGlobalPlugins': (list, ConfigInfo), + 'getInfoByPlugin': (list, AddonInfo), + 'getInteractionTask': InteractionTask, + 'getLog': (list, basestring), + 'getNotifications': (list, InteractionTask), + 'getPackageContent': TreeCollection, + 'getPackageInfo': PackageInfo, + 'getProgressInfo': (list, ProgressInfo), + 'getServerVersion': basestring, + 'getUserData': UserData, + 'getUserPlugins': (list, ConfigInfo), + 'hasAddonHandler': bool, + 'isInteractionWaiting': bool, + 'isTimeDownload': bool, + 'isTimeReconnect': bool, + 'kill': None, + 'login': bool, + 'moveFiles': bool, + 'movePackage': bool, + 'orderFiles': None, + 'orderPackage': None, + 'parseURLs': (dict, basestring, list), + 'pauseServer': None, + 'pollResults': OnlineCheck, + 'recheckPackage': None, + 'removeAccount': None, + 'removeUser': None, + 'renameCollPack': None, + 'restart': None, + 'restartFailed': None, + 'restartFile': None, + 'restartPackage': None, + 'saveConfig': None, + 'setConfigHandler': None, + 'setInteractionResult': None, + 'setPackageData': None, + 'setPackageFolder': bool, + 'setPackagePaused': None, + 'setPassword': bool, + 'statusServer': ServerStatus, + 'stopAllDownloads': None, + 'stopDownloads': None, + 'togglePause': bool, + 'toggleReconnect': bool, + 'unpauseServer': None, + 'updateAccount': None, + 'updateAccountInfo': None, + 'updateUserData': None, + 'uploadContainer': int, +} diff --git a/module/remote/wsbackend/AbstractHandler.py b/module/remote/wsbackend/AbstractHandler.py new file mode 100644 index 000000000..291dbf100 --- /dev/null +++ b/module/remote/wsbackend/AbstractHandler.py @@ -0,0 +1,79 @@ +#!/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 mod_pywebsocket.msgutil import send_message +from mod_pywebsocket.util import get_class_logger +from module.remote.json_converter import loads, dumps + + +class AbstractHandler: + """ + Abstract Handler providing common methods shared across WebSocket handlers + """ + + def __init__(self, api): + self.log = get_class_logger() + self.api = api + + def do_extra_handshake(self, req): + self.log.debug("WS Connected: %s" % req) + self.on_open(req) + + def on_open(self, req): + pass + + def passive_closing_handshake(self, req): + self.log.debug("WS Closed: %s" % req) + self.on_close(req) + + def on_close(self, req): + pass + + def transfer_data(self, req): + raise NotImplemented + + def handle_call(self, msg, req): + """ Parses the msg for an argument call. If func is null an response was already sent. + + :param msg: + :param req: + :return: func, args, kwargs + """ + try: + o = loads(msg) + except ValueError, e: #invalid json object + self.log.debug("Invalid Request: %s" % e) + return None, None, None + + if type(o) != list and len(o) > 2: + self.log.debug("Invalid Api call: %s" % o) + self.send_result(req, 500, "Invalid Api call") + return None, None, None + if len(o) == 1: # arguments omitted + o.append([]) + + func, args = o + if type(args) == list: + kwargs = {} + else: + args, kwargs = [], args + + return func, args, kwargs + + 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 478ea6de0..57d9ecd5b 100644 --- a/module/remote/wsbackend/ApiHandler.py +++ b/module/remote/wsbackend/ApiHandler.py @@ -16,11 +16,11 @@ # @author: RaNaN ############################################################################### -from mod_pywebsocket.util import get_class_logger -from mod_pywebsocket.msgutil import receive_message, send_message -from module.remote.json_converter import loads, dumps +from mod_pywebsocket.msgutil import receive_message -class ApiHandler: +from AbstractHandler import AbstractHandler + +class ApiHandler(AbstractHandler): """Provides access to the API. Send your request as json encoded string in the following manner: @@ -34,44 +34,22 @@ class ApiHandler: Non json request will be ignored. """ - def __init__(self, api): - self.log = get_class_logger() - self.api = api - - def do_extra_handshake(self, req): - self.log.debug("WS Connected: %s" % req) - def transfer_data(self, req): - while True: try: line = receive_message(req) - self.handle_message(line, req) except TypeError, e: # connection closed - print e + self.log.debug("WS Error: %s" % e) + self.passive_closing_handshake(req) return - def passive_closing_handshake(self, req): - self.log.debug("WS Closed: %s" % req) + self.handle_message(line, req) def handle_message(self, msg, req): - try: - o = loads(msg) - except ValueError, e: #invalid json object - self.log.debug("Invalid Request: %s" % e) - return - - if type(o) != list and len(o) > 2: - self.log.debug("Invalid Api call: %s" % o) - return self.send_result(req, 500, "Invalid Api call") - if len(o) == 1: # arguments omitted - o.append([]) - - func, args = o - if type(args) == list: - kwargs = {} - else: - args, kwargs = [], args + + 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) @@ -103,8 +81,4 @@ class ApiHandler: # None is invalid json type if result is None: result = True - return self.send_result(req, 200, result) - - - def send_result(self, req, code, result): - return send_message(req, dumps([code, result]))
\ No newline at end of file + return self.send_result(req, 200, result)
\ No newline at end of file diff --git a/module/remote/wsbackend/EventHandler.py b/module/remote/wsbackend/EventHandler.py index deab25a6c..2550ff2eb 100644 --- a/module/remote/wsbackend/EventHandler.py +++ b/module/remote/wsbackend/EventHandler.py @@ -16,26 +16,26 @@ # @author: RaNaN ############################################################################### -from mod_pywebsocket.msgutil import receive_message, send_message +from threading import Lock -class EventHandler: - def __init__(self, api): - self.api = api +from module.utils import lock +from AbstractHandler import AbstractHandler - def do_extra_handshake(self, req): - pass +class EventHandler(AbstractHandler): - def transfer_data(self, req): + def __init__(self, api): + AbstractHandler.__init__(self, api) + self.clients = [] + self.lock = Lock() - while True: - try: - line = receive_message(req) - except TypeError: # connection closed - return + @lock + def on_open(self, req): + self.clients.append(req) - print "Got", line - send_message(req, "You send: %s" % line) + @lock + def on_close(self, req): + self.clients.remove(req) - def passive_closing_handshake(self, req): - print "Closed", req
\ No newline at end of file + def handle_message(self, line, req): + pass
\ No newline at end of file |