From 0d2d6daef850ac6bcc7fafccd230e52d2a862c2c Mon Sep 17 00:00:00 2001 From: RaNaN Date: Sun, 3 Jun 2012 17:45:10 +0200 Subject: updates for database + api --- module/AccountManager.py | 140 +++ module/Api.py | 60 +- module/FileManager.py | 10 +- module/PluginManager.py | 403 +++++++ module/PyFile.py | 285 ----- module/PyPackage.py | 109 -- module/database/DatabaseBackend.py | 30 +- module/database/StatisticDatabase.py | 13 + module/database/UserDatabase.py | 117 +- module/datatypes/PyFile.py | 285 +++++ module/datatypes/PyPackage.py | 109 ++ module/datatypes/User.py | 33 + module/datatypes/__init__.py | 1 + module/plugins/AccountManager.py | 141 --- module/plugins/Addon.py | 14 +- module/plugins/PluginManager.py | 405 ------- module/plugins/hoster/MegauploadCom.py | 6 +- module/remote/socketbackend/ttypes.py | 35 +- module/remote/thriftbackend/pyload.thrift | 64 +- .../thriftbackend/thriftgen/pyload/Pyload-remote | 119 +- .../thriftbackend/thriftgen/pyload/Pyload.py | 1215 ++++++++++---------- .../thriftbackend/thriftgen/pyload/ttypes.py | 115 +- module/threads/ThreadManager.py | 32 +- module/utils/__init__.py | 9 + 24 files changed, 1898 insertions(+), 1852 deletions(-) create mode 100644 module/AccountManager.py create mode 100644 module/PluginManager.py delete mode 100644 module/PyFile.py delete mode 100644 module/PyPackage.py create mode 100644 module/database/StatisticDatabase.py create mode 100644 module/datatypes/PyFile.py create mode 100644 module/datatypes/PyPackage.py create mode 100644 module/datatypes/User.py create mode 100644 module/datatypes/__init__.py delete mode 100644 module/plugins/AccountManager.py delete mode 100644 module/plugins/PluginManager.py (limited to 'module') diff --git a/module/AccountManager.py b/module/AccountManager.py new file mode 100644 index 000000000..45b4eef95 --- /dev/null +++ b/module/AccountManager.py @@ -0,0 +1,140 @@ +#!/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, mkaay +############################################################################### + +from threading import Lock +from random import choice + +from module.common.json_layer import json +from module.utils import lock + +class AccountManager: + """manages all accounts""" + + def __init__(self, core): + """Constructor""" + + self.core = core + self.lock = Lock() + + self.loadAccounts() + + def loadAccounts(self): + """loads all accounts available""" + + self.accounts = {} + + for plugin, loginname, activated, password, options in self.core.db.loadAccounts(): + # put into options as used in other context + options = json.loads(options) if options else {} + options["activated"] = activated + + self.createAccount(plugin, loginname, password, options) + + return + + def iterAccounts(self): + """ yields login, account for all accounts""" + for name, data in self.accounts.iteritems(): + for login, account in data.iteritems(): + yield login, account + + def saveAccounts(self): + """save all account information""" + + data = [] + for name, plugin in self.accounts.iteritems(): + data.extend([(name, acc.loginname, acc.activated, acc.password, json.dumps(acc.options)) for acc in + plugin.itervalues()]) + self.core.db.saveAccounts(data) + + def createAccount(self, plugin, loginname, password, options): + klass = self.core.pluginManager.loadClass("accounts", plugin) + if not klass: + self.core.log.warning(_("Unknown account plugin %s") % plugin) + return + + if plugin not in self.accounts: + self.accounts[plugin] = {} + + self.core.log.debug("Create account %s:%s" % (plugin, loginname)) + + self.accounts[plugin][loginname] = klass(self, loginname, password, options) + + + def getAccount(self, plugin, user): + return self.accounts[plugin].get(user, None) + + @lock + def updateAccount(self, plugin, user, password=None, options={}): + """add or update account""" + if plugin in self.accounts and user in self.accounts[plugin]: + acc = self.accounts[plugin][user] + updated = acc.update(password, options) + + self.saveAccounts() + if updated: acc.scheduleRefresh(force=True) + else: + self.createAccount(plugin, user, password, options) + self.saveAccounts() + + self.sendChange(plugin, user) + + @lock + def removeAccount(self, plugin, user): + """remove account""" + if plugin in self.accounts and user in self.accounts[plugin]: + del self.accounts[plugin][user] + self.core.db.removeAccount(plugin, user) + self.core.eventManager.dispatchEvent("accountDeleted", plugin, user) + else: + self.core.log.debug("Remove non existing account %s %s" % (plugin, user)) + + + @lock + def getAccountForPlugin(self, plugin): + if plugin in self.accounts: + accs = [x for x in self.accounts[plugin].values() if x.isUsable()] + if accs: return choice(accs) + + return None + + @lock + def getAllAccounts(self, refresh=False): + """ Return account info, refresh afterwards if needed + + :param refresh: + :return: + """ + if refresh: + self.core.scheduler.addJob(0, self.core.accountManager.getAllAccounts) + + # load unavailable account info + for p_dict in self.accounts.itervalues(): + for acc in p_dict.itervalues(): + acc.getAccountInfo() + + return self.accounts + + def refreshAllAccounts(self): + """ Force a refresh of every account """ + for p in self.accounts.itervalues(): + for acc in p.itervalues(): + acc.getAccountInfo(True) + + def sendChange(self, plugin, name): + self.core.eventManager.dispatchEvent("accountUpdated", plugin, name) \ No newline at end of file diff --git a/module/Api.py b/module/Api.py index bab039ea1..388dfd283 100644 --- a/module/Api.py +++ b/module/Api.py @@ -1,21 +1,20 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: RaNaN -""" +############################################################################### +# 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 +############################################################################### import re from os.path import join, isabs @@ -38,8 +37,8 @@ if activated: else: from remote.socketbackend.ttypes import * -from PyFile import PyFile -from utils import compare_time, to_string, bits_set +from datatypes import PyFile +from utils import compare_time, to_string, bits_set, get_index from utils.fs import free_space from common.packagetools import parseNames from network.RequestFactory import getURL @@ -60,7 +59,7 @@ def RequirePerm(bits): return _Dec -# we will bytehacking the method to add user as keyword argument +# we will byte-hacking the method to add user as keyword argument class UserContext(object): """Decorator to mark methods that require a specific user""" @@ -68,7 +67,7 @@ class UserContext(object): fc = f.func_code try: - i = fc.co_names.index("user") + i = get_index(fc.co_names, "user") except ValueError: # functions does not uses user, so no need to modify return f @@ -119,6 +118,7 @@ class UserApi(object): return f +# TODO: fix permissions, user context manager class Api(Iface): """ @@ -144,7 +144,7 @@ class Api(Iface): print self.t.getServerVersion() - # TODO, create user instance, work + # TODO, create user instance def withUserContext(self, user): """ Returns a proxy version of the api, to call method in user context @@ -165,7 +165,7 @@ class Api(Iface): print user return self.core.version - @RequirePerm(Permission.List) + @RequirePerm(Permission.Status) def statusServer(self): """Some general information about the current status of pyLoad. @@ -588,7 +588,7 @@ class Api(Iface): # Collector ########################## - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getCollector(self): pass @@ -616,17 +616,17 @@ class Api(Iface): # File Information retrival ############################# - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getAllFiles(self): """ same as `getFileTree` for toplevel root and full tree""" return self.getFileTree(-1, True) - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getAllUnfinishedFiles(self): """ same as `getUnfinishedFileTree for toplevel root and full tree""" return self.getUnfinishedFileTree(-1, True) - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getFileTree(self, pid, full): """ Retrieve data for specific package. full=True will retrieve all data available and can result in greater delays. @@ -637,7 +637,7 @@ class Api(Iface): """ return self.core.files.getView(pid, full, False) - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getUnfinishedFileTree(self, pid, full): """ Same as `getFileTree` but only contains unfinished files. @@ -647,12 +647,12 @@ class Api(Iface): """ return self.core.files.getView(pid, full, False) - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getPackageContent(self, pid): """ Only retrieve content of a specific package. see `getFileTree`""" return self.getFileTree(pid, False) - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getPackageInfo(self, pid): """Returns information about package, without detailed information about containing files @@ -665,7 +665,7 @@ class Api(Iface): raise PackageDoesNotExists(pid) return info - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def getFileInfo(self, fid): """ Info for specific file @@ -679,7 +679,7 @@ class Api(Iface): raise FileDoesNotExists(fid) return info - @RequirePerm(Permission.List) + @RequirePerm(Permission.All) def findFiles(self, pattern): pass diff --git a/module/FileManager.py b/module/FileManager.py index 5a0d2b958..9d3c9a9cc 100644 --- a/module/FileManager.py +++ b/module/FileManager.py @@ -5,7 +5,8 @@ # Copyright(c) 2008-2012 pyLoad Team # http://www.pyload.org # -# This program is free software: you can redistribute it and/or modify +# 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. @@ -17,11 +18,12 @@ from time import time from threading import RLock + from module.utils import lock -from Api import PackageStatus, DownloadStatus as DS, PackageView, PackageDoesNotExists, FileDoesNotExists -from PyFile import PyFile -from PyPackage import PyPackage, RootPackage +from Api import PackageStatus, DownloadStatus as DS, PackageView, PackageDoesNotExists +from datatypes import PyFile, PyPackage +from datatypes.PyPackage import RootPackage # invalidates the cache def invalidate(func): diff --git a/module/PluginManager.py b/module/PluginManager.py new file mode 100644 index 000000000..81a5ee81c --- /dev/null +++ b/module/PluginManager.py @@ -0,0 +1,403 @@ +# -*- 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, mkaay +############################################################################### + +import re +import sys + +from os import listdir, makedirs +from os.path import isfile, join, exists, abspath, basename +from sys import version_info +from time import time + +from module.lib.SafeEval import const_eval as literal_eval +from module.plugins.Base import Base + +from new_collections import namedtuple + +#TODO: ignores not updatable + +# ignore these plugin configs, mainly because plugins were wiped out +IGNORE = ( + "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('addons', 'UnRar'), + 'EasyShareCom', 'FlyshareCz' + ) + +PluginTuple = namedtuple("PluginTuple", "version re deps user path") + +class PluginManager: + ROOT = "module.plugins." + USERROOT = "userplugins." + TYPES = ("crypter", "hoster", "accounts", "addons", "internal") + + BUILTIN = re.compile(r'__(?P[a-z0-9_]+)__\s*=\s?(True|False|None|[0-9x.]+)', re.I) + SINGLE = re.compile(r'__(?P[a-z0-9_]+)__\s*=\s*(?:r|u|_)?((?:(?[a-z0-9_]+)__\s*=\s*((?:\{|\[|"{3}).*?(?:"""|\}|\]))', re.DOTALL | re.M | re.I) + + def __init__(self, core): + self.core = core + + #self.config = self.core.config + self.log = core.log + + self.plugins = {} + self.modules = {} # cached modules + self.history = [] # match history to speedup parsing (type, name) + self.createIndex() + + self.core.config.parseValues(self.core.config.PLUGIN) + + #register for import addon + sys.meta_path.append(self) + + + def logDebug(self, type, plugin, msg): + self.log.debug("Plugin %s | %s: %s" % (type, plugin, msg)) + + def createIndex(self): + """create information for all plugins available""" + # add to path, so we can import from userplugins + sys.path.append(abspath("")) + + if not exists("userplugins"): + makedirs("userplugins") + if not exists(join("userplugins", "__init__.py")): + f = open(join("userplugins", "__init__.py"), "wb") + f.close() + + a = time() + for type in self.TYPES: + self.plugins[type] = self.parse(type) + + self.log.debug("Created index of plugins in %.2f ms", (time() - a) * 1000) + + def parse(self, folder, home=None): + """ Analyze and parses all plugins in folder """ + plugins = {} + if home: + pfolder = join("userplugins", folder) + if not exists(pfolder): + makedirs(pfolder) + if not exists(join(pfolder, "__init__.py")): + f = open(join(pfolder, "__init__.py"), "wb") + f.close() + + else: + pfolder = join(pypath, "module", "plugins", folder) + + for f in listdir(pfolder): + if (isfile(join(pfolder, f)) and f.endswith(".py") or f.endswith("_25.pyc") or f.endswith( + "_26.pyc") or f.endswith("_27.pyc")) and not f.startswith("_"): + if f.endswith("_25.pyc") and version_info[0:2] != (2, 5): + continue + elif f.endswith("_26.pyc") and version_info[0:2] != (2, 6): + continue + elif f.endswith("_27.pyc") and version_info[0:2] != (2, 7): + continue + + # replace suffix and version tag + name = f[:-3] + if name[-1] == ".": name = name[:-4] + + plugin = self.parsePlugin(join(pfolder, f), folder, name, home) + if plugin: + plugins[name] = plugin + + if not home: + temp = self.parse(folder, plugins) + plugins.update(temp) + + return plugins + + def parseAttributes(self, filename, name, folder=""): + """ Parse attribute dict from plugin""" + data = open(filename, "rb") + content = data.read() + data.close() + + attrs = {} + for m in self.BUILTIN.findall(content) + self.SINGLE.findall(content) + self.MULTI.findall(content): + #replace gettext function and eval result + try: + attrs[m[0]] = literal_eval(m[-1].replace("_(", "(")) + except: + self.logDebug(folder, name, "Error when parsing: %s" % m[-1]) + self.core.print_exc() + + if not hasattr(Base, "__%s__" % m[0]): + if m[0] != "type": #TODO remove type from all plugins, its not needed + self.logDebug(folder, name, "Unknown attribute '%s'" % m[0]) + + return attrs + + def parsePlugin(self, filename, folder, name, home=None): + """ Parses a plugin from disk, folder means plugin type in this context. Also sets config. + + :arg home: dict with plugins, of which the found one will be matched against (according version) + :returns PluginTuple""" + + attrs = self.parseAttributes(filename, name, folder) + if not attrs: return + + version = 0 + + if "version" in attrs: + try: + version = float(attrs["version"]) + except ValueError: + self.logDebug(folder, name, "Invalid version %s" % attrs["version"]) + version = 9 #TODO remove when plugins are fixed, causing update loops + else: + self.logDebug(folder, name, "No version attribute") + + # home contains plugins from pyload root + if home and name in home: + if home[name].version >= version: + return + + if name in IGNORE or (folder, name) in IGNORE: + return + + if "pattern" in attrs and attrs["pattern"]: + try: + plugin_re = re.compile(attrs["pattern"]) + except: + self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"]) + plugin_re = None + else: plugin_re = None + + deps = attrs.get("dependencies", None) + + # create plugin tuple + plugin = PluginTuple(version, plugin_re, deps, bool(home), filename) + + + # internals have no config + if folder == "internal": + return plugin + + if folder == "addons" and "config" not in attrs and not attrs.get("internal", False): + attrs["config"] = (["activated", "bool", "Activated", False],) + + if "config" in attrs and attrs["config"]: + config = attrs["config"] + desc = attrs.get("description", "") + long_desc = attrs.get("long_description", "") + + if type(config[0]) == tuple: + config = [list(x) for x in config] + else: + config = [list(config)] + + if folder == "addons" and not attrs.get("internal", False): + for item in config: + if item[0] == "activated": break + else: # activated flag missing + config.insert(0, ("activated", "bool", "Activated", False)) + + try: + self.core.config.addConfigSection(name, name, desc, long_desc, config) + except: + self.logDebug(folder, name, "Invalid config %s" % config) + + return plugin + + + def parseUrls(self, urls): + """parse plugins for given list of urls, separate to crypter and hoster""" + + res = {"hoster": [], "crypter": []} # tupels of (url, plugin) + + for url in urls: + if type(url) not in (str, unicode, buffer): + self.log.debug("Parsing invalid type %s" % type(url)) + continue + + found = False + + for ptype, name in self.history: + if self.plugins[ptype][name].re.match(url): + res[ptype].append((url, name)) + found = (ptype, name) + break # need to exit this loop first + + if found: # found match + if self.history[0] != found: #update history + self.history.remove(found) + self.history.insert(0, found) + continue + + for ptype in ("crypter", "hoster"): + for name, plugin in self.plugins[ptype].iteritems(): + if plugin.re.match(url): + res[ptype].append((url, name)) + self.history.insert(0, (ptype, name)) + del self.history[10:] # cut down to size of 10 + found = True + break + + if not found: + res["hoster"].append((url, "BasePlugin")) + + return res["hoster"], res["crypter"] + + def getPlugins(self, type): + return self.plugins.get(type, None) + + def findPlugin(self, name, pluginlist=("hoster", "crypter")): + for ptype in pluginlist: + if name in self.plugins[ptype]: + return ptype, self.plugins[ptype][name] + return None, None + + def getPluginModule(self, name): + """ Decprecated: return plugin module from hoster|crypter""" + self.log.debug("Deprecated method: .getPluginModule()") + type, plugin = self.findPlugin(name) + return self.loadModule(type, name) + + def getPluginClass(self, name): + """ return plugin class from hoster|crypter, always the not overwritten one """ + type, plugin = self.findPlugin(name) + return self.loadClass(type, name) + + # MultiHoster will overwrite this + getPlugin = getPluginClass + + + def loadAttributes(self, type, name): + plugin = self.plugins[type][name] + return self.parseAttributes(plugin.path, name, type) + + + def loadModule(self, type, name): + """ Returns loaded module for plugin + + :param type: plugin type, subfolder of module.plugins + :param name: + """ + plugins = self.plugins[type] + if name in plugins: + if (type, name) in self.modules: return self.modules[(type, name)] + try: + # convert path to python recognizable import + path = basename(plugins[name].path).replace(".pyc", "").replace(".py", "") + module = __import__(self.ROOT + "%s.%s" % (type, path), globals(), locals(), path) + self.modules[(type, name)] = module # cache import, maybe unneeded + return module + except Exception, e: + self.log.error(_("Error importing %(name)s: %(msg)s") % {"name": name, "msg": str(e)}) + self.core.print_exc() + + def loadClass(self, type, name): + """Returns the class of a plugin with the same name""" + module = self.loadModule(type, name) + if module: return getattr(module, name) + + def find_module(self, fullname, path=None): + #redirecting imports if necesarry + if fullname.startswith(self.ROOT) or fullname.startswith(self.USERROOT): #separate pyload plugins + if fullname.startswith(self.USERROOT): user = 1 + else: user = 0 #used as bool and int + + split = fullname.split(".") + if len(split) != 4 - user: return + type, name = split[2 - user:4 - user] + + if type in self.plugins and name in self.plugins[type]: + #userplugin is a newer version + if not user and self.plugins[type][name].user: + return self + #imported from userdir, but pyloads is newer + if user and not self.plugins[type][name].user: + return self + + + def load_module(self, name, replace=True): + if name not in sys.modules: #could be already in modules + if replace: + if self.ROOT in name: + newname = name.replace(self.ROOT, self.USERROOT) + else: + newname = name.replace(self.USERROOT, self.ROOT) + else: newname = name + + base, plugin = newname.rsplit(".", 1) + + self.log.debug("Redirected import %s -> %s" % (name, newname)) + + module = __import__(newname, globals(), locals(), [plugin]) + #inject under new an old name + sys.modules[name] = module + sys.modules[newname] = module + + return sys.modules[name] + + + def reloadPlugins(self, type_plugins): + """ reloads and reindexes plugins """ + if not type_plugins: return False + + self.log.debug("Request reload of plugins: %s" % type_plugins) + + as_dict = {} + for t, n in type_plugins: + if t in as_dict: + as_dict[t].append(n) + else: + as_dict[t] = [n] + + # we do not reload addons or internals, would cause to much side effects + if "addons" in as_dict or "internal" in as_dict: + return False + + for type in as_dict.iterkeys(): + for plugin in as_dict[type]: + if plugin in self.plugins[type]: + if (type, plugin) in self.modules: + self.log.debug("Reloading %s" % plugin) + reload(self.modules[(type, plugin)]) + + # index re-creation + for type in ("crypter", "container", "hoster", "captcha", "accounts"): + self.plugins[type] = self.parse(type) + + if "accounts" in as_dict: #accounts needs to be reloaded + self.core.accountManager.initPlugins() + self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos) + + return True + + def loadIcons(self): + """Loads all icons from plugins, plugin type is not in result, because its not important here. + + :return: Dict of names mapped to icons + """ + pass + + def loadIcon(self, type, name): + """ load icon for single plugin, base64 encoded""" + pass + + def checkDependencies(self, type, name): + """ Check deps for given plugin + + :return: List of unfullfilled dependencies + """ + pass + diff --git a/module/PyFile.py b/module/PyFile.py deleted file mode 100644 index 4cd0488a0..000000000 --- a/module/PyFile.py +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -############################################################################### -# Copyright(c) 2008-2012 pyLoad Team -# http://www.pyload.org -# -# This program 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 time import sleep, time -from threading import RLock - -from module.utils import format_size, format_time, lock - -from Api import FileInfo, DownloadInfo, DownloadStatus - -statusMap = { - "none": 0, - "offline": 1, - "online": 2, - "queued": 3, - "paused": 4, - "finished": 5, - "skipped": 6, - "failed": 7, - "starting": 8, - "waiting": 9, - "downloading": 10, - "temp. offline": 11, - "aborted": 12, - "decrypting": 13, - "processing": 14, - "custom": 15, - "unknown": 16, - } - -class PyFile(object): - """ - Represents a file object at runtime - """ - __slots__ = ("m", "fid", "_name", "_size", "filestatus", "media", "added", "fileorder", - "url", "pluginname", "hash", "status", "error", "packageid", "ownerid", - "lock", "plugin", "waitUntil", "active", "abort", "statusname", - "reconnected", "progress", "maxprogress", "pluginclass") - - @staticmethod - def fromInfoData(m, info): - f = PyFile(m, info.fid, info.name, info.size, info.status, info.media, info.added, info.fileorder, - "", "", "", DownloadStatus.NA, "", info.package, info.owner) - if info.download: - f.url = info.download.url - f.pluginname = info.download.plugin - f.hash = info.download.hash - f.status = info.download.status - f.error = info.download.error - - return f - - def __init__(self, manager, fid, name, size, filestatus, media, added, fileorder, - url, pluginname, hash, status, error, package, owner): - - self.m = manager - - self.fid = int(fid) - self._name = name - self._size = size - self.filestatus = filestatus - self.media = media - self.added = added - self.fileorder = fileorder - self.url = url - self.pluginname = pluginname - self.hash = hash - self.status = status - self.error = error - self.ownerid = owner - self.packageid = package #should not be used, use package() instead - # database information ends here - - self.lock = RLock() - - self.plugin = None - #self.download = None - - self.waitUntil = 0 # time() + time to wait - - # status attributes - self.active = False #obsolete? - self.abort = False - self.reconnected = False - - self.statusname = None - - self.progress = 0 - self.maxprogress = 100 - - @property - def id(self): - self.m.core.log.debug("Deprecated attr .id, use .fid instead") - return self.fid - - def setSize(self, value): - self._size = int(value) - - # will convert all sizes to ints - size = property(lambda self: self._size, setSize) - - def getName(self): - try: - if self.plugin.req.name: - return self.plugin.req.name - else: - return self._name - except: - return self._name - - def setName(self, name): - """ Only set unicode or utf8 strings as name """ - if type(name) == str: - name = name.decode("utf8") - - self._name = name - - name = property(getName, setName) - - def __repr__(self): - return "" % (self.id, self.name, self.pluginname) - - @lock - def initPlugin(self): - """ inits plugin instance """ - if not self.plugin: - self.pluginclass = self.m.core.pluginManager.getPlugin(self.pluginname) - self.plugin = self.pluginclass(self) - - @lock - def hasPlugin(self): - """Thread safe way to determine this file has initialized plugin attribute""" - return hasattr(self, "plugin") and self.plugin - - def package(self): - """ return package instance""" - return self.m.getPackage(self.packageid) - - def setStatus(self, status): - self.status = statusMap[status] - # needs to sync so status is written to database - self.sync() - - def setCustomStatus(self, msg, status="processing"): - self.statusname = msg - self.setStatus(status) - - def getStatusName(self): - if self.status not in (13, 14) or not self.statusname: - return self.m.statusMsg[self.status] - else: - return self.statusname - - def hasStatus(self, status): - return statusMap[status] == self.status - - def sync(self): - """sync PyFile instance with database""" - self.m.updateFile(self) - - @lock - def release(self): - """sync and remove from cache""" - if hasattr(self, "plugin") and self.plugin: - self.plugin.clean() - del self.plugin - - self.m.releaseFile(self.fid) - - - def toInfoData(self): - return FileInfo(self.fid, self.getName(), self.packageid, self.ownerid, self.getSize(), self.filestatus, - self.media, self.added, self.fileorder, DownloadInfo( - self.url, self.pluginname, self.hash, self.status, self.getStatusName(), self.error - ) - ) - - def getPath(self): - pass - - def move(self, pid): - pass - - def abortDownload(self): - """abort pyfile if possible""" - while self.id in self.m.core.threadManager.processingIds(): - self.abort = True - if self.plugin and self.plugin.req: - self.plugin.req.abortDownloads() - sleep(0.1) - - self.abort = False - if self.hasPlugin() and self.plugin.req: - self.plugin.req.abortDownloads() - - self.release() - - def finishIfDone(self): - """set status to finish and release file if every thread is finished with it""" - - if self.id in self.m.core.threadManager.processingIds(): - return False - - self.setStatus("finished") - self.release() - self.m.checkAllLinksFinished() - return True - - def checkIfProcessed(self): - self.m.checkAllLinksProcessed(self.id) - - def formatWait(self): - """ formats and return wait time in humanreadable format """ - return format_time(self.waitUntil - time()) - - def formatSize(self): - """ formats size to readable format """ - return format_size(self.getSize()) - - def formatETA(self): - """ formats eta to readable format """ - return format_time(self.getETA()) - - def getSpeed(self): - """ calculates speed """ - try: - return self.plugin.req.speed - except: - return 0 - - def getETA(self): - """ gets established time of arrival""" - try: - return self.getBytesLeft() / self.getSpeed() - except: - return 0 - - def getBytesLeft(self): - """ gets bytes left """ - try: - return self.plugin.req.size - self.plugin.req.arrived - except: - return 0 - - def getPercent(self): - """ get % of download """ - if self.status == DownloadStatus.Downloading: - try: - return self.plugin.req.percent - except: - return 0 - else: - return self.progress - - def getSize(self): - """ get size of download """ - try: - if self.plugin.req.size: - return self.plugin.req.size - else: - return self.size - except: - return self.size - - def notifyChange(self): - self.m.core.eventManager.dispatchEvent("linkUpdated", self.id, self.packageid) - - def setProgress(self, value): - if not value == self.progress: - self.progress = value - self.notifyChange() diff --git a/module/PyPackage.py b/module/PyPackage.py deleted file mode 100644 index 1dc2754ef..000000000 --- a/module/PyPackage.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -############################################################################### -# Copyright(c) 2008-2012 pyLoad Team -# http://www.pyload.org -# -# This program 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 time import time - -from module.utils.fs import join - -from Api import PackageInfo, PackageStatus - -class PyPackage: - """ - Represents a package object at runtime - """ - - @staticmethod - def fromInfoData(m, info): - return PyPackage(m, info.pid, info.name, info.folder, info.root, info.owner, - info.site, info.comment, info.password, info.added, info.status, info.packageorder) - - def __init__(self, manager, pid, name, folder, root, owner, site, comment, password, added, status, packageorder): - self.m = manager - - self.pid = pid - self.name = name - self.folder = folder - self.root = root - self.ownerid = owner - self.site = site - self.comment = comment - self.password = password - self.added = added - self.status = status - self.packageorder = packageorder - self.timestamp = time() - - @property - def id(self): - self.m.core.log.debug("Deprecated package attr .id, use .pid instead") - return self.pid - - def isStale(self): - return self.timestamp + 30 * 60 > time() - - def toInfoData(self): - return PackageInfo(self.pid, self.name, self.folder, self.root, self.ownerid, self.site, - self.comment, self.password, self.added, self.status, self.packageorder - ) - - def getChildren(self): - """get information about contained links""" - return self.m.getPackageData(self.id)["links"] - - def getPath(self, name=""): - self.timestamp = time() - return join(self.m.getPackage(self.root).getPath(), self.folder, name) - - def sync(self): - """sync with db""" - self.m.updatePackage(self) - - def release(self): - """sync and delete from cache""" - self.sync() - self.m.releasePackage(self.id) - - def delete(self): - self.m.deletePackage(self.id) - - def deleteIfEmpty(self): - """ True if deleted """ - if not len(self.getChildren()): - self.delete() - return True - return False - - def notifyChange(self): - self.m.core.eventManager.dispatchEvent("packageUpdated", self.id) - - -class RootPackage(PyPackage): - def __init__(self, m, owner): - PyPackage.__init__(self, m, -1, "root", "", owner, -2, "", "", "", 0, PackageStatus.Ok, 0) - - def getPath(self, name=""): - return join(self.m.core.config["general"]["download_folder"], name) - - # no database operations - def sync(self): - pass - - def delete(self): - pass - - def release(self): - pass \ No newline at end of file diff --git a/module/database/DatabaseBackend.py b/module/database/DatabaseBackend.py index ec39e3fd9..2c494e520 100644 --- a/module/database/DatabaseBackend.py +++ b/module/database/DatabaseBackend.py @@ -5,15 +5,15 @@ # Copyright(c) 2008-2012 pyLoad Team # http://www.pyload.org # -# This program is free software: you can redistribute it and/or modify +# 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 -# @author: mkaay +# @author: RaNaN, mkaay ############################################################################### from threading import Thread, Event @@ -268,7 +268,6 @@ class DatabaseBackend(Thread): 'UPDATE packages SET packageorder=packageorder-1 WHERE packageorder > old.packageorder AND root=old.pid;' 'END' ) - self.c.execute('CREATE INDEX IF NOT EXISTS "package_index" ON packages(root, owner)') self.c.execute('CREATE INDEX IF NOT EXISTS "package_owner" ON packages(owner)') @@ -292,7 +291,6 @@ class DatabaseBackend(Thread): 'FOREIGN KEY(package) REFERENCES packages(id)' ')' ) - self.c.execute('CREATE INDEX IF NOT EXISTS "file_index" ON files(package, owner)') self.c.execute('CREATE INDEX IF NOT EXISTS "file_owner" ON files(owner)') @@ -309,7 +307,7 @@ class DatabaseBackend(Thread): 'CREATE TABLE IF NOT EXISTS "collector" (' '"owner" INTEGER NOT NULL, ' '"data" TEXT NOT NULL, ' - 'FOREIGN KEY(owner) REFERENCES users(uid)' + 'FOREIGN KEY(owner) REFERENCES users(uid), ' 'PRIMARY KEY(owner) ON CONFLICT REPLACE' ') ' ) @@ -326,7 +324,7 @@ class DatabaseBackend(Thread): self.c.execute( 'CREATE TABLE IF NOT EXISTS "users" (' '"uid" INTEGER PRIMARY KEY AUTOINCREMENT, ' - '"name" TEXT NOT NULL, ' + '"name" TEXT NOT NULL UNIQUE, ' '"email" TEXT DEFAULT "" NOT NULL, ' '"password" TEXT NOT NULL, ' '"role" INTEGER DEFAULT 0 NOT NULL, ' @@ -334,12 +332,13 @@ class DatabaseBackend(Thread): '"folder" TEXT DEFAULT "" NOT NULL, ' '"traffic" INTEGER DEFAULT -1 NOT NULL, ' '"dllimit" INTEGER DEFAULT -1 NOT NULL, ' + '"dlquota" TEXT DEFAULT "" NOT NULL, ' + '"hddquota" INTEGER DEFAULT -1 NOT NULL, ' '"template" TEXT DEFAULT "default" NOT NULL, ' '"user" INTEGER DEFAULT -1 NOT NULL, ' # set by trigger to self 'FOREIGN KEY(user) REFERENCES users(uid)' ')' ) - self.c.execute('CREATE INDEX IF NOT EXISTS "username_index" ON users(name)') self.c.execute( @@ -369,11 +368,24 @@ class DatabaseBackend(Thread): '"password" TEXT DEFAULT "", ' '"shared" INTEGER DEFAULT 0, ' '"options" TEXT DEFAULT "", ' - 'FOREIGN KEY(owner) REFERENCES users(uid)' + 'FOREIGN KEY(owner) REFERENCES users(uid), ' 'PRIMARY KEY (plugin, loginname, owner) ON CONFLICT REPLACE' ')' ) + self.c.execute( + 'CREATE TABLE IF NOT EXISTS "stats" (' + '"user" INTEGER NOT NULL, ' + '"plugin" TEXT NOT NULL, ' + '"time" INTEGER NOT NULL, ' + '"premium" INTEGER DEFAULT 0 NOT NULL, ' + '"amount" INTEGER DEFAULT 0 NOT NULL, ' + 'FOREIGN KEY(user) REFERENCES users(uid), ' + 'PRIMARY KEY(user, plugin, time)' + ')' + ) + self.c.execute('CREATE INDEX IF NOT EXISTS "stats_time" ON stats(time)') + #try to lower ids self.c.execute('SELECT max(fid) FROM files') fid = self.c.fetchone()[0] diff --git a/module/database/StatisticDatabase.py b/module/database/StatisticDatabase.py new file mode 100644 index 000000000..10619eb5b --- /dev/null +++ b/module/database/StatisticDatabase.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from module.database import DatabaseMethods, queue, async, inner + +# TODO + +class StatisticMethods(DatabaseMethods): + pass + + + +StatisticMethods.register() \ No newline at end of file diff --git a/module/database/UserDatabase.py b/module/database/UserDatabase.py index 6bfb02bbd..bed4e94a9 100644 --- a/module/database/UserDatabase.py +++ b/module/database/UserDatabase.py @@ -1,42 +1,28 @@ # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: mkaay -""" +############################################################################### +# 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 hashlib import sha1 import random +from module.Api import UserData + from DatabaseBackend import DatabaseMethods, queue, async class UserMethods(DatabaseMethods): - @queue - def checkAuth(self, user, password): - self.c.execute('SELECT rowid, name, password, role, permission, template, email FROM "users" WHERE name=?', (user, )) - r = self.c.fetchone() - if not r: - return {} - - salt = r[2][:5] - pw = r[2][5:] - h = sha1(salt + password) - if h.hexdigest() == pw: - return {"id": r[0], "name": r[1], "role": r[3], - "permission": r[4], "template": r[5], "email": r[6]} - else: - return {} @queue def addUser(self, user, password): @@ -50,8 +36,53 @@ class UserMethods(DatabaseMethods): else: self.c.execute('INSERT INTO users (name, password) VALUES (?, ?)', (user, password)) + @queue + def getUserData(self, name=None, uid=None): + qry = ('SELECT uid, name, email, role, permission, folder, traffic, dllimit, dlquota, ' + 'hddquota, user, template FROM "users" WHERE ') + + if name is not None: + self.c.execute(qry + "name=?", (name,)) + r = self.c.fetchone() + if r: + return UserData(*r) + + elif uid is not None: + self.c.execute(qry + "uid=?", (uid,)) + r = self.c.fetchone() + if r: + return UserData(*r) + + return None @queue + def getAllUserData(self): + self.c.execute('SELECT uid, name, email, role, permission, folder, traffic, dllimit, dlquota, ' + 'hddquota, user, template FROM "users"') + user = {} + for r in self.c: + user[r[0]] = UserData(*r) + + return user + + + @queue + def checkAuth(self, user, password): + self.c.execute('SELECT uid, name, email, role, permission, folder, traffic, dllimit, dlquota, ' + 'hddquota, user, template password FROM "users" WHERE name=?', (user, )) + r = self.c.fetchone() + if not r: + return None + + salt = r[-1][:5] + pw = r[-1][5:] + h = sha1(salt + password) + if h.hexdigest() == pw: + return UserData(*r[:-1]) + else: + return None + + @queue #TODO def changePassword(self, user, oldpw, newpw): self.c.execute('SELECT rowid, name, password FROM users WHERE name=?', (user, )) r = self.c.fetchone() @@ -71,7 +102,6 @@ class UserMethods(DatabaseMethods): return False - @async def setPermission(self, user, perms): self.c.execute("UPDATE users SET permission=? WHERE name=?", (perms, user)) @@ -80,26 +110,11 @@ class UserMethods(DatabaseMethods): def setRole(self, user, role): self.c.execute("UPDATE users SET role=? WHERE name=?", (role, user)) + # TODO update methods - @queue - def listUsers(self): - self.c.execute('SELECT name FROM users') - users = [] - for row in self.c: - users.append(row[0]) - return users - - @queue - def getAllUserData(self): - self.c.execute("SELECT name, permission, role, template, email FROM users") - user = {} - for r in self.c: - user[r[0]] = {"permission": r[1], "role": r[2], "template": r[3], "email": r[4]} - - return user - - @queue - def removeUser(self, user): - self.c.execute('DELETE FROM users WHERE name=?', (user, )) + @async + def removeUser(self, uid=None): + # deletes user and all associated accounts + self.c.execute('DELETE FROM users WHERE user=?', (uid, )) UserMethods.register() diff --git a/module/datatypes/PyFile.py b/module/datatypes/PyFile.py new file mode 100644 index 000000000..1a515493c --- /dev/null +++ b/module/datatypes/PyFile.py @@ -0,0 +1,285 @@ +#!/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 time import sleep, time +from threading import RLock + +from module.Api import FileInfo, DownloadInfo, DownloadStatus +from module.utils import format_size, format_time, lock + +statusMap = { + "none": 0, + "offline": 1, + "online": 2, + "queued": 3, + "paused": 4, + "finished": 5, + "skipped": 6, + "failed": 7, + "starting": 8, + "waiting": 9, + "downloading": 10, + "temp. offline": 11, + "aborted": 12, + "decrypting": 13, + "processing": 14, + "custom": 15, + "unknown": 16, + } + +class PyFile(object): + """ + Represents a file object at runtime + """ + __slots__ = ("m", "fid", "_name", "_size", "filestatus", "media", "added", "fileorder", + "url", "pluginname", "hash", "status", "error", "packageid", "ownerid", + "lock", "plugin", "waitUntil", "active", "abort", "statusname", + "reconnected", "progress", "maxprogress", "pluginclass") + + @staticmethod + def fromInfoData(m, info): + f = PyFile(m, info.fid, info.name, info.size, info.status, info.media, info.added, info.fileorder, + "", "", "", DownloadStatus.NA, "", info.package, info.owner) + if info.download: + f.url = info.download.url + f.pluginname = info.download.plugin + f.hash = info.download.hash + f.status = info.download.status + f.error = info.download.error + + return f + + def __init__(self, manager, fid, name, size, filestatus, media, added, fileorder, + url, pluginname, hash, status, error, package, owner): + + self.m = manager + + self.fid = int(fid) + self._name = name + self._size = size + self.filestatus = filestatus + self.media = media + self.added = added + self.fileorder = fileorder + self.url = url + self.pluginname = pluginname + self.hash = hash + self.status = status + self.error = error + self.ownerid = owner + self.packageid = package #should not be used, use package() instead + # database information ends here + + self.lock = RLock() + + self.plugin = None + #self.download = None + + self.waitUntil = 0 # time() + time to wait + + # status attributes + self.active = False #obsolete? + self.abort = False + self.reconnected = False + + self.statusname = None + + self.progress = 0 + self.maxprogress = 100 + + @property + def id(self): + self.m.core.log.debug("Deprecated attr .id, use .fid instead") + return self.fid + + def setSize(self, value): + self._size = int(value) + + # will convert all sizes to ints + size = property(lambda self: self._size, setSize) + + def getName(self): + try: + if self.plugin.req.name: + return self.plugin.req.name + else: + return self._name + except: + return self._name + + def setName(self, name): + """ Only set unicode or utf8 strings as name """ + if type(name) == str: + name = name.decode("utf8") + + self._name = name + + name = property(getName, setName) + + def __repr__(self): + return "" % (self.id, self.name, self.pluginname) + + @lock + def initPlugin(self): + """ inits plugin instance """ + if not self.plugin: + self.pluginclass = self.m.core.pluginManager.getPlugin(self.pluginname) + self.plugin = self.pluginclass(self) + + @lock + def hasPlugin(self): + """Thread safe way to determine this file has initialized plugin attribute""" + return hasattr(self, "plugin") and self.plugin + + def package(self): + """ return package instance""" + return self.m.getPackage(self.packageid) + + def setStatus(self, status): + self.status = statusMap[status] + # needs to sync so status is written to database + self.sync() + + def setCustomStatus(self, msg, status="processing"): + self.statusname = msg + self.setStatus(status) + + def getStatusName(self): + if self.status not in (13, 14) or not self.statusname: + return self.m.statusMsg[self.status] + else: + return self.statusname + + def hasStatus(self, status): + return statusMap[status] == self.status + + def sync(self): + """sync PyFile instance with database""" + self.m.updateFile(self) + + @lock + def release(self): + """sync and remove from cache""" + if hasattr(self, "plugin") and self.plugin: + self.plugin.clean() + del self.plugin + + self.m.releaseFile(self.fid) + + + def toInfoData(self): + return FileInfo(self.fid, self.getName(), self.packageid, self.ownerid, self.getSize(), self.filestatus, + self.media, self.added, self.fileorder, DownloadInfo( + self.url, self.pluginname, self.hash, self.status, self.getStatusName(), self.error + ) + ) + + def getPath(self): + pass + + def move(self, pid): + pass + + def abortDownload(self): + """abort pyfile if possible""" + while self.id in self.m.core.threadManager.processingIds(): + self.abort = True + if self.plugin and self.plugin.req: + self.plugin.req.abortDownloads() + sleep(0.1) + + self.abort = False + if self.hasPlugin() and self.plugin.req: + self.plugin.req.abortDownloads() + + self.release() + + def finishIfDone(self): + """set status to finish and release file if every thread is finished with it""" + + if self.id in self.m.core.threadManager.processingIds(): + return False + + self.setStatus("finished") + self.release() + self.m.checkAllLinksFinished() + return True + + def checkIfProcessed(self): + self.m.checkAllLinksProcessed(self.id) + + def formatWait(self): + """ formats and return wait time in humanreadable format """ + return format_time(self.waitUntil - time()) + + def formatSize(self): + """ formats size to readable format """ + return format_size(self.getSize()) + + def formatETA(self): + """ formats eta to readable format """ + return format_time(self.getETA()) + + def getSpeed(self): + """ calculates speed """ + try: + return self.plugin.req.speed + except: + return 0 + + def getETA(self): + """ gets established time of arrival""" + try: + return self.getBytesLeft() / self.getSpeed() + except: + return 0 + + def getBytesLeft(self): + """ gets bytes left """ + try: + return self.plugin.req.size - self.plugin.req.arrived + except: + return 0 + + def getPercent(self): + """ get % of download """ + if self.status == DownloadStatus.Downloading: + try: + return self.plugin.req.percent + except: + return 0 + else: + return self.progress + + def getSize(self): + """ get size of download """ + try: + if self.plugin.req.size: + return self.plugin.req.size + else: + return self.size + except: + return self.size + + def notifyChange(self): + self.m.core.eventManager.dispatchEvent("linkUpdated", self.id, self.packageid) + + def setProgress(self, value): + if not value == self.progress: + self.progress = value + self.notifyChange() diff --git a/module/datatypes/PyPackage.py b/module/datatypes/PyPackage.py new file mode 100644 index 000000000..be2f23eea --- /dev/null +++ b/module/datatypes/PyPackage.py @@ -0,0 +1,109 @@ +#!/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 time import time + +from module.Api import PackageInfo, PackageStatus +from module.utils.fs import join + +class PyPackage: + """ + Represents a package object at runtime + """ + + @staticmethod + def fromInfoData(m, info): + return PyPackage(m, info.pid, info.name, info.folder, info.root, info.owner, + info.site, info.comment, info.password, info.added, info.status, info.packageorder) + + def __init__(self, manager, pid, name, folder, root, owner, site, comment, password, added, status, packageorder): + self.m = manager + + self.pid = pid + self.name = name + self.folder = folder + self.root = root + self.ownerid = owner + self.site = site + self.comment = comment + self.password = password + self.added = added + self.status = status + self.packageorder = packageorder + self.timestamp = time() + + @property + def id(self): + self.m.core.log.debug("Deprecated package attr .id, use .pid instead") + return self.pid + + def isStale(self): + return self.timestamp + 30 * 60 > time() + + def toInfoData(self): + return PackageInfo(self.pid, self.name, self.folder, self.root, self.ownerid, self.site, + self.comment, self.password, self.added, self.status, self.packageorder + ) + + def getChildren(self): + """get information about contained links""" + return self.m.getPackageData(self.id)["links"] + + def getPath(self, name=""): + self.timestamp = time() + return join(self.m.getPackage(self.root).getPath(), self.folder, name) + + def sync(self): + """sync with db""" + self.m.updatePackage(self) + + def release(self): + """sync and delete from cache""" + self.sync() + self.m.releasePackage(self.id) + + def delete(self): + self.m.deletePackage(self.id) + + def deleteIfEmpty(self): + """ True if deleted """ + if not len(self.getChildren()): + self.delete() + return True + return False + + def notifyChange(self): + self.m.core.eventManager.dispatchEvent("packageUpdated", self.id) + + +class RootPackage(PyPackage): + def __init__(self, m, owner): + PyPackage.__init__(self, m, -1, "root", "", owner, -2, "", "", "", 0, PackageStatus.Ok, 0) + + def getPath(self, name=""): + return join(self.m.core.config["general"]["download_folder"], name) + + # no database operations + def sync(self): + pass + + def delete(self): + pass + + def release(self): + pass \ No newline at end of file diff --git a/module/datatypes/User.py b/module/datatypes/User.py new file mode 100644 index 000000000..6ea958770 --- /dev/null +++ b/module/datatypes/User.py @@ -0,0 +1,33 @@ +#!/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 module.Api import UserData + +#noinspection PyUnresolvedReferences +class User(UserData): + + @staticmethod + def fromUserData(manager, user): + return User(manager, user.uid, user.name, user.email, user.role, user.permission, user.folder, + user.traffic, user.dllimit, user.dlquota, user.hddquota, user.user, user.templateName) + + def __init__(self, manager, *args): + UserData.__init__(*args) + self.m = manager + diff --git a/module/datatypes/__init__.py b/module/datatypes/__init__.py new file mode 100644 index 000000000..4b31e848b --- /dev/null +++ b/module/datatypes/__init__.py @@ -0,0 +1 @@ +__author__ = 'christian' diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py deleted file mode 100644 index c610d10e0..000000000 --- a/module/plugins/AccountManager.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: RaNaN -""" - -from threading import Lock -from random import choice - -from module.common.json_layer import json -from module.utils import lock - -class AccountManager: - """manages all accounts""" - - def __init__(self, core): - """Constructor""" - - self.core = core - self.lock = Lock() - - self.loadAccounts() - - def loadAccounts(self): - """loads all accounts available""" - - self.accounts = {} - - for plugin, loginname, activated, password, options in self.core.db.loadAccounts(): - # put into options as used in other context - options = json.loads(options) if options else {} - options["activated"] = activated - - self.createAccount(plugin, loginname, password, options) - - return - - def iterAccounts(self): - """ yields login, account for all accounts""" - for name, data in self.accounts.iteritems(): - for login, account in data.iteritems(): - yield login, account - - def saveAccounts(self): - """save all account information""" - - data = [] - for name, plugin in self.accounts.iteritems(): - data.extend([(name, acc.loginname, acc.activated, acc.password, json.dumps(acc.options)) for acc in - plugin.itervalues()]) - self.core.db.saveAccounts(data) - - def createAccount(self, plugin, loginname, password, options): - klass = self.core.pluginManager.loadClass("accounts", plugin) - if not klass: - self.core.log.warning(_("Unknown account plugin %s") % plugin) - return - - if plugin not in self.accounts: - self.accounts[plugin] = {} - - self.core.log.debug("Create account %s:%s" % (plugin, loginname)) - - self.accounts[plugin][loginname] = klass(self, loginname, password, options) - - - def getAccount(self, plugin, user): - return self.accounts[plugin].get(user, None) - - @lock - def updateAccount(self, plugin, user, password=None, options={}): - """add or update account""" - if plugin in self.accounts and user in self.accounts[plugin]: - acc = self.accounts[plugin][user] - updated = acc.update(password, options) - - self.saveAccounts() - if updated: acc.scheduleRefresh(force=True) - else: - self.createAccount(plugin, user, password, options) - self.saveAccounts() - - self.sendChange(plugin, user) - - @lock - def removeAccount(self, plugin, user): - """remove account""" - if plugin in self.accounts and user in self.accounts[plugin]: - del self.accounts[plugin][user] - self.core.db.removeAccount(plugin, user) - self.core.eventManager.dispatchEvent("accountDeleted", plugin, user) - else: - self.core.log.debug("Remove non existing account %s %s" % (plugin, user)) - - - @lock - def getAccountForPlugin(self, plugin): - if plugin in self.accounts: - accs = [x for x in self.accounts[plugin].values() if x.isUsable()] - if accs: return choice(accs) - - return None - - @lock - def getAllAccounts(self, refresh=False): - """ Return account info, refresh afterwards if needed - - :param refresh: - :return: - """ - if refresh: - self.core.scheduler.addJob(0, self.core.accountManager.getAllAccounts) - - # load unavailable account info - for p_dict in self.accounts.itervalues(): - for acc in p_dict.itervalues(): - acc.getAccountInfo() - - return self.accounts - - def refreshAllAccounts(self): - """ Force a refresh of every account """ - for p in self.accounts.itervalues(): - for acc in p.itervalues(): - acc.getAccountInfo(True) - - def sendChange(self, plugin, name): - self.core.eventManager.dispatchEvent("accountUpdated", plugin, name) \ No newline at end of file diff --git a/module/plugins/Addon.py b/module/plugins/Addon.py index 614c68c80..60223dd28 100644 --- a/module/plugins/Addon.py +++ b/module/plugins/Addon.py @@ -27,11 +27,6 @@ from Base import Base def class_name(p): return p.rpartition(".")[2] -class Expose(object): - """ Used for decoration to declare rpc services. You can use any arbitrary method """ - def __new__(cls, f, *args, **kwargs): - addonManager.addRPC(class_name(f.__module__), f.func_name, f.func_doc) - return f def AddEventListener(event): """ Used to register method for events. Arguments needs to match parameter of event @@ -59,13 +54,12 @@ class ConfigHandler(object): addonManager.addConfigHandler(class_name(f.__module__), f.func_name) return f -def FileHandler(desc, media, package=False): - """ Register Handler for Files or packages. - Depending on package=True the decorated method needs to accept pid or fid as argument +def AddonHandler(desc, media=None): + """ Register Handler for files, packages, or arbitrary callable methods. + To let the method work on packages/files, media must be set and the argument named pid or fid. :param desc: verbose description - :param media: media type for which your method will be used - :param package: True if it works on packages + :param media: if True or bits of media type """ pass diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py deleted file mode 100644 index f42bd08c6..000000000 --- a/module/plugins/PluginManager.py +++ /dev/null @@ -1,405 +0,0 @@ -# -*- coding: utf-8 -*- - -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: mkaay, RaNaN -""" - -import re -import sys - -from os import listdir, makedirs -from os.path import isfile, join, exists, abspath, basename -from sys import version_info -from time import time - -from module.lib.SafeEval import const_eval as literal_eval -from module.plugins.Base import Base - -from new_collections import namedtuple - -#TODO: ignores not updatable - -# ignore these plugin configs, mainly because plugins were wiped out -IGNORE = ( - "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('addons', 'UnRar'), - 'EasyShareCom', 'FlyshareCz' - ) - -PluginTuple = namedtuple("PluginTuple", "version re deps user path") - -class PluginManager: - ROOT = "module.plugins." - USERROOT = "userplugins." - TYPES = ("crypter", "hoster", "accounts", "addons", "internal") - - BUILTIN = re.compile(r'__(?P[a-z0-9_]+)__\s*=\s?(True|False|None|[0-9x.]+)', re.I) - SINGLE = re.compile(r'__(?P[a-z0-9_]+)__\s*=\s*(?:r|u|_)?((?:(?[a-z0-9_]+)__\s*=\s*((?:\{|\[|"{3}).*?(?:"""|\}|\]))', re.DOTALL | re.M | re.I) - - def __init__(self, core): - self.core = core - - #self.config = self.core.config - self.log = core.log - - self.plugins = {} - self.modules = {} # cached modules - self.history = [] # match history to speedup parsing (type, name) - self.createIndex() - - self.core.config.parseValues(self.core.config.PLUGIN) - - #register for import addon - sys.meta_path.append(self) - - - def logDebug(self, type, plugin, msg): - self.log.debug("Plugin %s | %s: %s" % (type, plugin, msg)) - - def createIndex(self): - """create information for all plugins available""" - # add to path, so we can import from userplugins - sys.path.append(abspath("")) - - if not exists("userplugins"): - makedirs("userplugins") - if not exists(join("userplugins", "__init__.py")): - f = open(join("userplugins", "__init__.py"), "wb") - f.close() - - a = time() - for type in self.TYPES: - self.plugins[type] = self.parse(type) - - self.log.debug("Created index of plugins in %.2f ms", (time() - a) * 1000) - - def parse(self, folder, home=None): - """ Analyze and parses all plugins in folder """ - plugins = {} - if home: - pfolder = join("userplugins", folder) - if not exists(pfolder): - makedirs(pfolder) - if not exists(join(pfolder, "__init__.py")): - f = open(join(pfolder, "__init__.py"), "wb") - f.close() - - else: - pfolder = join(pypath, "module", "plugins", folder) - - for f in listdir(pfolder): - if (isfile(join(pfolder, f)) and f.endswith(".py") or f.endswith("_25.pyc") or f.endswith( - "_26.pyc") or f.endswith("_27.pyc")) and not f.startswith("_"): - if f.endswith("_25.pyc") and version_info[0:2] != (2, 5): - continue - elif f.endswith("_26.pyc") and version_info[0:2] != (2, 6): - continue - elif f.endswith("_27.pyc") and version_info[0:2] != (2, 7): - continue - - # replace suffix and version tag - name = f[:-3] - if name[-1] == ".": name = name[:-4] - - plugin = self.parsePlugin(join(pfolder, f), folder, name, home) - if plugin: - plugins[name] = plugin - - if not home: - temp = self.parse(folder, plugins) - plugins.update(temp) - - return plugins - - def parseAttributes(self, filename, name, folder=""): - """ Parse attribute dict from plugin""" - data = open(filename, "rb") - content = data.read() - data.close() - - attrs = {} - for m in self.BUILTIN.findall(content) + self.SINGLE.findall(content) + self.MULTI.findall(content): - #replace gettext function and eval result - try: - attrs[m[0]] = literal_eval(m[-1].replace("_(", "(")) - except: - self.logDebug(folder, name, "Error when parsing: %s" % m[-1]) - self.core.print_exc() - - if not hasattr(Base, "__%s__" % m[0]): - if m[0] != "type": #TODO remove type from all plugins, its not needed - self.logDebug(folder, name, "Unknown attribute '%s'" % m[0]) - - return attrs - - def parsePlugin(self, filename, folder, name, home=None): - """ Parses a plugin from disk, folder means plugin type in this context. Also sets config. - - :arg home: dict with plugins, of which the found one will be matched against (according version) - :returns PluginTuple""" - - attrs = self.parseAttributes(filename, name, folder) - if not attrs: return - - version = 0 - - if "version" in attrs: - try: - version = float(attrs["version"]) - except ValueError: - self.logDebug(folder, name, "Invalid version %s" % attrs["version"]) - version = 9 #TODO remove when plugins are fixed, causing update loops - else: - self.logDebug(folder, name, "No version attribute") - - # home contains plugins from pyload root - if home and name in home: - if home[name].version >= version: - return - - if name in IGNORE or (folder, name) in IGNORE: - return - - if "pattern" in attrs and attrs["pattern"]: - try: - plugin_re = re.compile(attrs["pattern"]) - except: - self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"]) - plugin_re = None - else: plugin_re = None - - deps = attrs.get("dependencies", None) - - # create plugin tuple - plugin = PluginTuple(version, plugin_re, deps, bool(home), filename) - - - # internals have no config - if folder == "internal": - return plugin - - if folder == "addons" and "config" not in attrs and not attrs.get("internal", False): - attrs["config"] = (["activated", "bool", "Activated", False],) - - if "config" in attrs and attrs["config"]: - config = attrs["config"] - desc = attrs.get("description", "") - long_desc = attrs.get("long_description", "") - - if type(config[0]) == tuple: - config = [list(x) for x in config] - else: - config = [list(config)] - - if folder == "addons" and not attrs.get("internal", False): - for item in config: - if item[0] == "activated": break - else: # activated flag missing - config.insert(0, ("activated", "bool", "Activated", False)) - - try: - self.core.config.addConfigSection(name, name, desc, long_desc, config) - except: - self.logDebug(folder, name, "Invalid config %s" % config) - - return plugin - - - def parseUrls(self, urls): - """parse plugins for given list of urls, separate to crypter and hoster""" - - res = {"hoster": [], "crypter": []} # tupels of (url, plugin) - - for url in urls: - if type(url) not in (str, unicode, buffer): - self.log.debug("Parsing invalid type %s" % type(url)) - continue - - found = False - - for ptype, name in self.history: - if self.plugins[ptype][name].re.match(url): - res[ptype].append((url, name)) - found = (ptype, name) - break # need to exit this loop first - - if found: # found match - if self.history[0] != found: #update history - self.history.remove(found) - self.history.insert(0, found) - continue - - for ptype in ("crypter", "hoster"): - for name, plugin in self.plugins[ptype].iteritems(): - if plugin.re.match(url): - res[ptype].append((url, name)) - self.history.insert(0, (ptype, name)) - del self.history[10:] # cut down to size of 10 - found = True - break - - if not found: - res["hoster"].append((url, "BasePlugin")) - - return res["hoster"], res["crypter"] - - def getPlugins(self, type): - return self.plugins.get(type, None) - - def findPlugin(self, name, pluginlist=("hoster", "crypter")): - for ptype in pluginlist: - if name in self.plugins[ptype]: - return ptype, self.plugins[ptype][name] - return None, None - - def getPluginModule(self, name): - """ Decprecated: return plugin module from hoster|crypter""" - self.log.debug("Deprecated method: .getPluginModule()") - type, plugin = self.findPlugin(name) - return self.loadModule(type, name) - - def getPluginClass(self, name): - """ return plugin class from hoster|crypter, always the not overwritten one """ - type, plugin = self.findPlugin(name) - return self.loadClass(type, name) - - # MultiHoster will overwrite this - getPlugin = getPluginClass - - - def loadAttributes(self, type, name): - plugin = self.plugins[type][name] - return self.parseAttributes(plugin.path, name, type) - - - def loadModule(self, type, name): - """ Returns loaded module for plugin - - :param type: plugin type, subfolder of module.plugins - :param name: - """ - plugins = self.plugins[type] - if name in plugins: - if (type, name) in self.modules: return self.modules[(type, name)] - try: - # convert path to python recognizable import - path = basename(plugins[name].path).replace(".pyc", "").replace(".py", "") - module = __import__(self.ROOT + "%s.%s" % (type, path), globals(), locals(), path) - self.modules[(type, name)] = module # cache import, maybe unneeded - return module - except Exception, e: - self.log.error(_("Error importing %(name)s: %(msg)s") % {"name": name, "msg": str(e)}) - self.core.print_exc() - - def loadClass(self, type, name): - """Returns the class of a plugin with the same name""" - module = self.loadModule(type, name) - if module: return getattr(module, name) - - def find_module(self, fullname, path=None): - #redirecting imports if necesarry - if fullname.startswith(self.ROOT) or fullname.startswith(self.USERROOT): #separate pyload plugins - if fullname.startswith(self.USERROOT): user = 1 - else: user = 0 #used as bool and int - - split = fullname.split(".") - if len(split) != 4 - user: return - type, name = split[2 - user:4 - user] - - if type in self.plugins and name in self.plugins[type]: - #userplugin is a newer version - if not user and self.plugins[type][name].user: - return self - #imported from userdir, but pyloads is newer - if user and not self.plugins[type][name].user: - return self - - - def load_module(self, name, replace=True): - if name not in sys.modules: #could be already in modules - if replace: - if self.ROOT in name: - newname = name.replace(self.ROOT, self.USERROOT) - else: - newname = name.replace(self.USERROOT, self.ROOT) - else: newname = name - - base, plugin = newname.rsplit(".", 1) - - self.log.debug("Redirected import %s -> %s" % (name, newname)) - - module = __import__(newname, globals(), locals(), [plugin]) - #inject under new an old name - sys.modules[name] = module - sys.modules[newname] = module - - return sys.modules[name] - - - def reloadPlugins(self, type_plugins): - """ reloads and reindexes plugins """ - if not type_plugins: return False - - self.log.debug("Request reload of plugins: %s" % type_plugins) - - as_dict = {} - for t, n in type_plugins: - if t in as_dict: - as_dict[t].append(n) - else: - as_dict[t] = [n] - - # we do not reload addons or internals, would cause to much side effects - if "addons" in as_dict or "internal" in as_dict: - return False - - for type in as_dict.iterkeys(): - for plugin in as_dict[type]: - if plugin in self.plugins[type]: - if (type, plugin) in self.modules: - self.log.debug("Reloading %s" % plugin) - reload(self.modules[(type, plugin)]) - - # index re-creation - for type in ("crypter", "container", "hoster", "captcha", "accounts"): - self.plugins[type] = self.parse(type) - - if "accounts" in as_dict: #accounts needs to be reloaded - self.core.accountManager.initPlugins() - self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos) - - return True - - def loadIcons(self): - """Loads all icons from plugins, plugin type is not in result, because its not important here. - - :return: Dict of names mapped to icons - """ - pass - - def loadIcon(self, type, name): - """ load icon for single plugin, base64 encoded""" - pass - - def checkDependencies(self, type, name): - """ Check deps for given plugin - - :return: List of unfullfilled dependencies - """ - pass - diff --git a/module/plugins/hoster/MegauploadCom.py b/module/plugins/hoster/MegauploadCom.py index 336cbfb58..8693e4303 100644 --- a/module/plugins/hoster/MegauploadCom.py +++ b/module/plugins/hoster/MegauploadCom.py @@ -2,17 +2,13 @@ # -*- coding: utf-8 -*- import re -from time import sleep from module.plugins.Hoster import Hoster from module.network.RequestFactory import getURL -from module.network.HTTPRequest import BadHeader from module.utils import html_unescape -from module.PyFile import statusMap - -from pycurl import error +from datatypes.PyFile import statusMap def getInfo(urls): yield [(url, 0, 1, url) for url in urls] diff --git a/module/remote/socketbackend/ttypes.py b/module/remote/socketbackend/ttypes.py index 127098ec3..b7e0d7f3d 100644 --- a/module/remote/socketbackend/ttypes.py +++ b/module/remote/socketbackend/ttypes.py @@ -63,16 +63,15 @@ class PackageStatus: Remote = 2 class Permission: - Accounts = 128 + Accounts = 32 Add = 1 - Addons = 512 + Addons = 128 All = 0 Delete = 2 - Download = 64 - Interaction = 256 - List = 16 - Modify = 32 - Status = 4 + Download = 16 + Interaction = 64 + Modify = 4 + Status = 8 class Role: Admin = 0 @@ -103,13 +102,13 @@ class AddonInfo(BaseObject): self.value = value class AddonService(BaseObject): - __slots__ = ['func_name', 'description', 'media', 'package'] + __slots__ = ['func_name', 'description', 'arguments', 'media'] - def __init__(self, func_name=None, description=None, media=None, package=None): + def __init__(self, func_name=None, description=None, arguments=None, media=None): self.func_name = func_name self.description = description + self.arguments = arguments self.media = media - self.package = package class ConfigItem(BaseObject): __slots__ = ['name', 'display_name', 'description', 'type', 'default_value', 'value'] @@ -293,9 +292,9 @@ class ServiceException(Exception): self.msg = msg class UserData(BaseObject): - __slots__ = ['uid', 'name', 'email', 'role', 'permission', 'folder', 'traffic', 'dllimit', 'user', 'templateName'] + __slots__ = ['uid', 'name', 'email', 'role', 'permission', 'folder', 'traffic', 'dllimit', 'dlquota', 'hddquota', 'user', 'templateName'] - def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, dllimit=None, user=None, templateName=None): + def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, dllimit=None, dlquota=None, hddquota=None, user=None, templateName=None): self.uid = uid self.name = name self.email = email @@ -304,6 +303,8 @@ class UserData(BaseObject): self.folder = folder self.traffic = traffic self.dllimit = dllimit + self.dlquota = dlquota + self.hddquota = hddquota self.user = user self.templateName = templateName @@ -318,6 +319,8 @@ class Iface: pass def addLinks(self, pid, links): pass + def addLocalFile(self, pid, name, path): + pass def addPackage(self, name, links, password): pass def addPackageChild(self, name, links, password, root, paused): @@ -328,9 +331,7 @@ class Iface: pass def addUser(self, username, password): pass - def autoAddLinks(self, links): - pass - def call(self, plugin, func, arguments): + def callAddon(self, plugin, func, arguments): pass def callAddonHandler(self, plugin, func, pid_or_fid): pass @@ -406,13 +407,11 @@ class Iface: pass def getServerVersion(self): pass - def getServices(self): - pass def getUnfinishedFileTree(self, pid, full): pass def getUserData(self): pass - def hasService(self, plugin, func): + def hasAddonHandler(self, plugin, func): pass def isInteractionWaiting(self, mode): pass diff --git a/module/remote/thriftbackend/pyload.thrift b/module/remote/thriftbackend/pyload.thrift index 181ca4204..e0fa9c040 100644 --- a/module/remote/thriftbackend/pyload.thrift +++ b/module/remote/thriftbackend/pyload.thrift @@ -201,6 +201,13 @@ struct InteractionTask { 8: PluginName plugin, } +struct AddonService { + 1: string func_name, + 2: string description, + 3: list arguments, + 4: optional i16 media, +} + struct AddonInfo { 1: string func_name, 2: string description, @@ -228,7 +235,7 @@ struct ConfigSection { struct EventInfo { 1: string eventname, - 2: list event_args, + 2: list event_args, } struct UserData { @@ -240,8 +247,10 @@ struct UserData { 6: string folder, 7: ByteCount traffic 8: i16 dllimit - 9: UserID user - 10: string templateName + 9: string dlquota, + 10: ByteCount hddquota, + 11: UserID user + 12: string templateName } struct AccountInfo { @@ -258,13 +267,6 @@ struct AccountInfo { 11: map options, } -struct AddonService { - 1: string func_name, - 2: string description, - 3: optional i16 media, - 4: optional bool package, -} - struct OnlineCheck { 1: ResultID rid, // -1 -> nothing more to get 2: map data, // url to result @@ -313,9 +315,6 @@ service Pyload { bool toggleReconnect(), void scanDownloadFolder(), - // downloads - information - list getProgressInfo(), - /////////////////////// // Configuration /////////////////////// @@ -333,7 +332,6 @@ service Pyload { map checkURLs(1: LinkList urls), map parseURLs(1: string html, 2: string url), - // packagename - urls // parses results and generates packages OnlineCheck checkOnlineStatus(1: LinkList urls), @@ -342,6 +340,7 @@ service Pyload { // poll results from previously started online check OnlineCheck pollResults(1: ResultID rid), + // packagename -> urls map generatePackages(1: LinkList links), /////////////////////// @@ -349,7 +348,6 @@ service Pyload { /////////////////////// list generateAndAddPackages(1: LinkList links, 2: bool paused), - list autoAddLinks(1: LinkList links), PackageID createPackage(1: string name, 2: string folder, 3: PackageID root, 4: string password, 5: string site, 6: string comment, 7: bool paused), @@ -364,10 +362,11 @@ service Pyload { PackageID uploadContainer(1: string filename, 2: binary data), void addLinks(1: PackageID pid, 2: LinkList links) throws (1: PackageDoesNotExists e), + void addLocalFile(1: PackageID pid, 2: string name, 3: string path) throws (1: PackageDoesNotExists e) // these are real file operations and WILL delete files on disk void deleteFiles(1: list fids), - void deletePackages(1: list pids), + void deletePackages(1: list pids), // delete the whole folder recursive /////////////////////// // Collector @@ -406,8 +405,6 @@ service Pyload { void restartPackage(1: PackageID pid), void restartFile(1: FileID fid), void recheckPackage(1: PackageID pid), - void stopDownloads(1: list fids), - void stopAllDownloads(), void restartFailed(), ///////////////////////// @@ -428,6 +425,17 @@ service Pyload { void orderPackage(1: list pids, 2: i16 position), void orderFiles(1: list fids, 2: PackageID pid, 3: i16 position), + /////////////////////// + // Taks/Progress + /////////////////////// + + // downloads - information + list getProgressInfo(), + void stopDownloads(1: list fids), + void stopAllDownloads(), + + // TODO - progress methods and data type + /////////////////////// // User Interaction /////////////////////// @@ -442,9 +450,6 @@ service Pyload { list getNotifications(), - map> getAddonHandler(), - void callAddonHandler(1: PluginName plugin, 2: string func, 3: PackageID pid_or_fid), - /////////////////////// // Event Handling /////////////////////// @@ -484,15 +489,20 @@ service Pyload { // Addon Methods /////////////////////// - map> getServices(), - bool hasService(1: PluginName plugin, 2: string func), - - // empty string or json encoded list as args - string call(1: PluginName plugin, 2: string func, 3: JSONString arguments) throws (1: ServiceDoesNotExists ex, 2: ServiceException e), - map> getAllInfo(), list getInfoByPlugin(1: PluginName plugin), + map> getAddonHandler(), + bool hasAddonHandler(1: PluginName plugin, 2: string func), + + void callAddon(1: PluginName plugin, 2: string func, 3: list arguments) + throws (1: ServiceDoesNotExists e, 2: ServiceException ex), + + // special variant of callAddon that works on the media types, acccepting integer + void callAddonHandler(1: PluginName plugin, 2: string func, 3: PackageID pid_or_fid) + throws (1: ServiceDoesNotExists e, 2: ServiceException ex), + + //scheduler // TODO diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote b/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote index c2c13d8ed..5b4a6fc75 100755 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote +++ b/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote @@ -36,7 +36,6 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' bool isTimeReconnect()' print ' bool toggleReconnect()' print ' void scanDownloadFolder()' - print ' getProgressInfo()' print ' string getConfigValue(string section, string option)' print ' void setConfigValue(string section, string option, string value)' print ' getConfig()' @@ -50,13 +49,13 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' OnlineCheck pollResults(ResultID rid)' print ' generatePackages(LinkList links)' print ' generateAndAddPackages(LinkList links, bool paused)' - print ' autoAddLinks(LinkList links)' print ' PackageID createPackage(string name, string folder, PackageID root, string password, string site, string comment, bool paused)' print ' PackageID addPackage(string name, LinkList links, string password)' print ' PackageID addPackageP(string name, LinkList links, string password, bool paused)' print ' PackageID addPackageChild(string name, LinkList links, string password, PackageID root, bool paused)' print ' PackageID uploadContainer(string filename, string data)' print ' void addLinks(PackageID pid, LinkList links)' + print ' void addLocalFile(PackageID pid, string name, string path)' print ' void deleteFiles( fids)' print ' void deletePackages( pids)' print ' getCollector()' @@ -76,8 +75,6 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' void restartPackage(PackageID pid)' print ' void restartFile(FileID fid)' print ' void recheckPackage(PackageID pid)' - print ' void stopDownloads( fids)' - print ' void stopAllDownloads()' print ' void restartFailed()' print ' void setFilePaused(FileID fid, bool paused)' print ' void setPackagePaused(PackageID pid, bool paused)' @@ -87,13 +84,14 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' bool moveFiles( fids, PackageID pid)' print ' void orderPackage( pids, i16 position)' print ' void orderFiles( fids, PackageID pid, i16 position)' + print ' getProgressInfo()' + print ' void stopDownloads( fids)' + print ' void stopAllDownloads()' print ' bool isInteractionWaiting(i16 mode)' print ' InteractionTask getInteractionTask(i16 mode)' print ' void setInteractionResult(InteractionID iid, JSONString result)' print ' string generateDownloadLink(FileID fid, i16 timeout)' print ' getNotifications()' - print ' getAddonHandler()' - print ' void callAddonHandler(PluginName plugin, string func, PackageID pid_or_fid)' print ' getEvents(string uuid)' print ' getAccounts(bool refresh)' print ' getAccountTypes()' @@ -106,11 +104,12 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' void updateUserData(UserData data)' print ' void removeUser(UserID uid)' print ' bool setPassword(string username, string old_password, string new_password)' - print ' getServices()' - print ' bool hasService(PluginName plugin, string func)' - print ' string call(PluginName plugin, string func, JSONString arguments)' print ' getAllInfo()' print ' getInfoByPlugin(PluginName plugin)' + print ' getAddonHandler()' + print ' bool hasAddonHandler(PluginName plugin, string func)' + print ' void callAddon(PluginName plugin, string func, arguments)' + print ' void callAddonHandler(PluginName plugin, string func, PackageID pid_or_fid)' print '' sys.exit(0) @@ -240,12 +239,6 @@ elif cmd == 'scanDownloadFolder': sys.exit(1) pp.pprint(client.scanDownloadFolder()) -elif cmd == 'getProgressInfo': - if len(args) != 0: - print 'getProgressInfo requires 0 args' - sys.exit(1) - pp.pprint(client.getProgressInfo()) - elif cmd == 'getConfigValue': if len(args) != 2: print 'getConfigValue requires 2 args' @@ -324,12 +317,6 @@ elif cmd == 'generateAndAddPackages': sys.exit(1) pp.pprint(client.generateAndAddPackages(eval(args[0]),eval(args[1]),)) -elif cmd == 'autoAddLinks': - if len(args) != 1: - print 'autoAddLinks requires 1 args' - sys.exit(1) - pp.pprint(client.autoAddLinks(eval(args[0]),)) - elif cmd == 'createPackage': if len(args) != 7: print 'createPackage requires 7 args' @@ -366,6 +353,12 @@ elif cmd == 'addLinks': sys.exit(1) pp.pprint(client.addLinks(eval(args[0]),eval(args[1]),)) +elif cmd == 'addLocalFile': + if len(args) != 3: + print 'addLocalFile requires 3 args' + sys.exit(1) + pp.pprint(client.addLocalFile(eval(args[0]),args[1],args[2],)) + elif cmd == 'deleteFiles': if len(args) != 1: print 'deleteFiles requires 1 args' @@ -480,18 +473,6 @@ elif cmd == 'recheckPackage': sys.exit(1) pp.pprint(client.recheckPackage(eval(args[0]),)) -elif cmd == 'stopDownloads': - if len(args) != 1: - print 'stopDownloads requires 1 args' - sys.exit(1) - pp.pprint(client.stopDownloads(eval(args[0]),)) - -elif cmd == 'stopAllDownloads': - if len(args) != 0: - print 'stopAllDownloads requires 0 args' - sys.exit(1) - pp.pprint(client.stopAllDownloads()) - elif cmd == 'restartFailed': if len(args) != 0: print 'restartFailed requires 0 args' @@ -546,6 +527,24 @@ elif cmd == 'orderFiles': sys.exit(1) pp.pprint(client.orderFiles(eval(args[0]),eval(args[1]),eval(args[2]),)) +elif cmd == 'getProgressInfo': + if len(args) != 0: + print 'getProgressInfo requires 0 args' + sys.exit(1) + pp.pprint(client.getProgressInfo()) + +elif cmd == 'stopDownloads': + if len(args) != 1: + print 'stopDownloads requires 1 args' + sys.exit(1) + pp.pprint(client.stopDownloads(eval(args[0]),)) + +elif cmd == 'stopAllDownloads': + if len(args) != 0: + print 'stopAllDownloads requires 0 args' + sys.exit(1) + pp.pprint(client.stopAllDownloads()) + elif cmd == 'isInteractionWaiting': if len(args) != 1: print 'isInteractionWaiting requires 1 args' @@ -576,18 +575,6 @@ elif cmd == 'getNotifications': sys.exit(1) pp.pprint(client.getNotifications()) -elif cmd == 'getAddonHandler': - if len(args) != 0: - print 'getAddonHandler requires 0 args' - sys.exit(1) - pp.pprint(client.getAddonHandler()) - -elif cmd == 'callAddonHandler': - if len(args) != 3: - print 'callAddonHandler requires 3 args' - sys.exit(1) - pp.pprint(client.callAddonHandler(eval(args[0]),args[1],eval(args[2]),)) - elif cmd == 'getEvents': if len(args) != 1: print 'getEvents requires 1 args' @@ -660,24 +647,6 @@ elif cmd == 'setPassword': sys.exit(1) pp.pprint(client.setPassword(args[0],args[1],args[2],)) -elif cmd == 'getServices': - if len(args) != 0: - print 'getServices requires 0 args' - sys.exit(1) - pp.pprint(client.getServices()) - -elif cmd == 'hasService': - if len(args) != 2: - print 'hasService requires 2 args' - sys.exit(1) - pp.pprint(client.hasService(eval(args[0]),args[1],)) - -elif cmd == 'call': - if len(args) != 3: - print 'call requires 3 args' - sys.exit(1) - pp.pprint(client.call(eval(args[0]),args[1],eval(args[2]),)) - elif cmd == 'getAllInfo': if len(args) != 0: print 'getAllInfo requires 0 args' @@ -690,6 +659,30 @@ elif cmd == 'getInfoByPlugin': sys.exit(1) pp.pprint(client.getInfoByPlugin(eval(args[0]),)) +elif cmd == 'getAddonHandler': + if len(args) != 0: + print 'getAddonHandler requires 0 args' + sys.exit(1) + pp.pprint(client.getAddonHandler()) + +elif cmd == 'hasAddonHandler': + if len(args) != 2: + print 'hasAddonHandler requires 2 args' + sys.exit(1) + pp.pprint(client.hasAddonHandler(eval(args[0]),args[1],)) + +elif cmd == 'callAddon': + if len(args) != 3: + print 'callAddon requires 3 args' + sys.exit(1) + pp.pprint(client.callAddon(eval(args[0]),args[1],eval(args[2]),)) + +elif cmd == 'callAddonHandler': + if len(args) != 3: + print 'callAddonHandler requires 3 args' + sys.exit(1) + pp.pprint(client.callAddonHandler(eval(args[0]),args[1],eval(args[2]),)) + else: print 'Unrecognized method %s' % cmd sys.exit(1) diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py b/module/remote/thriftbackend/thriftgen/pyload/Pyload.py index dd446cfc3..ba5d8cadc 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py +++ b/module/remote/thriftbackend/thriftgen/pyload/Pyload.py @@ -56,9 +56,6 @@ class Iface(object): def scanDownloadFolder(self, ): pass - def getProgressInfo(self, ): - pass - def getConfigValue(self, section, option): """ Parameters: @@ -151,13 +148,6 @@ class Iface(object): """ pass - def autoAddLinks(self, links): - """ - Parameters: - - links - """ - pass - def createPackage(self, name, folder, root, password, site, comment, paused): """ Parameters: @@ -217,6 +207,15 @@ class Iface(object): """ pass + def addLocalFile(self, pid, name, path): + """ + Parameters: + - pid + - name + - path + """ + pass + def deleteFiles(self, fids): """ Parameters: @@ -342,16 +341,6 @@ class Iface(object): """ pass - def stopDownloads(self, fids): - """ - Parameters: - - fids - """ - pass - - def stopAllDownloads(self, ): - pass - def restartFailed(self, ): pass @@ -420,6 +409,19 @@ class Iface(object): """ pass + def getProgressInfo(self, ): + pass + + def stopDownloads(self, fids): + """ + Parameters: + - fids + """ + pass + + def stopAllDownloads(self, ): + pass + def isInteractionWaiting(self, mode): """ Parameters: @@ -453,18 +455,6 @@ class Iface(object): def getNotifications(self, ): pass - def getAddonHandler(self, ): - pass - - def callAddonHandler(self, plugin, func, pid_or_fid): - """ - Parameters: - - plugin - - func - - pid_or_fid - """ - pass - def getEvents(self, uuid): """ Parameters: @@ -545,33 +535,42 @@ class Iface(object): """ pass - def getServices(self, ): + def getAllInfo(self, ): pass - def hasService(self, plugin, func): + def getInfoByPlugin(self, plugin): """ Parameters: - plugin - - func """ pass - def call(self, plugin, func, arguments): + def getAddonHandler(self, ): + pass + + def hasAddonHandler(self, plugin, func): """ Parameters: - plugin - func - - arguments """ pass - def getAllInfo(self, ): + def callAddon(self, plugin, func, arguments): + """ + Parameters: + - plugin + - func + - arguments + """ pass - def getInfoByPlugin(self, plugin): + def callAddonHandler(self, plugin, func, pid_or_fid): """ Parameters: - plugin + - func + - pid_or_fid """ pass @@ -903,31 +902,6 @@ class Client(Iface): self._iprot.readMessageEnd() return - def getProgressInfo(self, ): - self.send_getProgressInfo() - return self.recv_getProgressInfo() - - def send_getProgressInfo(self, ): - self._oprot.writeMessageBegin('getProgressInfo', TMessageType.CALL, self._seqid) - args = getProgressInfo_args() - args.write(self._oprot) - self._oprot.writeMessageEnd() - self._oprot.trans.flush() - - def recv_getProgressInfo(self, ): - (fname, mtype, rseqid) = self._iprot.readMessageBegin() - if mtype == TMessageType.EXCEPTION: - x = TApplicationException() - x.read(self._iprot) - self._iprot.readMessageEnd() - raise x - result = getProgressInfo_result() - result.read(self._iprot) - self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getProgressInfo failed: unknown result"); - def getConfigValue(self, section, option): """ Parameters: @@ -1322,36 +1296,6 @@ class Client(Iface): return result.success raise TApplicationException(TApplicationException.MISSING_RESULT, "generateAndAddPackages failed: unknown result"); - def autoAddLinks(self, links): - """ - Parameters: - - links - """ - self.send_autoAddLinks(links) - return self.recv_autoAddLinks() - - def send_autoAddLinks(self, links): - self._oprot.writeMessageBegin('autoAddLinks', TMessageType.CALL, self._seqid) - args = autoAddLinks_args() - args.links = links - args.write(self._oprot) - self._oprot.writeMessageEnd() - self._oprot.trans.flush() - - def recv_autoAddLinks(self, ): - (fname, mtype, rseqid) = self._iprot.readMessageBegin() - if mtype == TMessageType.EXCEPTION: - x = TApplicationException() - x.read(self._iprot) - self._iprot.readMessageEnd() - raise x - result = autoAddLinks_result() - result.read(self._iprot) - self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "autoAddLinks failed: unknown result"); - def createPackage(self, name, folder, root, password, site, comment, paused): """ Parameters: @@ -1566,6 +1510,40 @@ class Client(Iface): raise result.e return + def addLocalFile(self, pid, name, path): + """ + Parameters: + - pid + - name + - path + """ + self.send_addLocalFile(pid, name, path) + self.recv_addLocalFile() + + def send_addLocalFile(self, pid, name, path): + self._oprot.writeMessageBegin('addLocalFile', TMessageType.CALL, self._seqid) + args = addLocalFile_args() + args.pid = pid + args.name = name + args.path = path + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_addLocalFile(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = addLocalFile_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + if result.e is not None: + raise result.e + return + def deleteFiles(self, fids): """ Parameters: @@ -2115,57 +2093,6 @@ class Client(Iface): self._iprot.readMessageEnd() return - def stopDownloads(self, fids): - """ - Parameters: - - fids - """ - self.send_stopDownloads(fids) - self.recv_stopDownloads() - - def send_stopDownloads(self, fids): - self._oprot.writeMessageBegin('stopDownloads', TMessageType.CALL, self._seqid) - args = stopDownloads_args() - args.fids = fids - args.write(self._oprot) - self._oprot.writeMessageEnd() - self._oprot.trans.flush() - - def recv_stopDownloads(self, ): - (fname, mtype, rseqid) = self._iprot.readMessageBegin() - if mtype == TMessageType.EXCEPTION: - x = TApplicationException() - x.read(self._iprot) - self._iprot.readMessageEnd() - raise x - result = stopDownloads_result() - result.read(self._iprot) - self._iprot.readMessageEnd() - return - - def stopAllDownloads(self, ): - self.send_stopAllDownloads() - self.recv_stopAllDownloads() - - def send_stopAllDownloads(self, ): - self._oprot.writeMessageBegin('stopAllDownloads', TMessageType.CALL, self._seqid) - args = stopAllDownloads_args() - args.write(self._oprot) - self._oprot.writeMessageEnd() - self._oprot.trans.flush() - - def recv_stopAllDownloads(self, ): - (fname, mtype, rseqid) = self._iprot.readMessageBegin() - if mtype == TMessageType.EXCEPTION: - x = TApplicationException() - x.read(self._iprot) - self._iprot.readMessageEnd() - raise x - result = stopAllDownloads_result() - result.read(self._iprot) - self._iprot.readMessageEnd() - return - def restartFailed(self, ): self.send_restartFailed() self.recv_restartFailed() @@ -2449,209 +2376,228 @@ class Client(Iface): self._iprot.readMessageEnd() return - def isInteractionWaiting(self, mode): - """ - Parameters: - - mode - """ - self.send_isInteractionWaiting(mode) - return self.recv_isInteractionWaiting() + def getProgressInfo(self, ): + self.send_getProgressInfo() + return self.recv_getProgressInfo() - def send_isInteractionWaiting(self, mode): - self._oprot.writeMessageBegin('isInteractionWaiting', TMessageType.CALL, self._seqid) - args = isInteractionWaiting_args() - args.mode = mode + def send_getProgressInfo(self, ): + self._oprot.writeMessageBegin('getProgressInfo', TMessageType.CALL, self._seqid) + args = getProgressInfo_args() args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_isInteractionWaiting(self, ): + def recv_getProgressInfo(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = isInteractionWaiting_result() + result = getProgressInfo_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "isInteractionWaiting failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "getProgressInfo failed: unknown result"); - def getInteractionTask(self, mode): + def stopDownloads(self, fids): """ Parameters: - - mode + - fids """ - self.send_getInteractionTask(mode) - return self.recv_getInteractionTask() + self.send_stopDownloads(fids) + self.recv_stopDownloads() - def send_getInteractionTask(self, mode): - self._oprot.writeMessageBegin('getInteractionTask', TMessageType.CALL, self._seqid) - args = getInteractionTask_args() - args.mode = mode + def send_stopDownloads(self, fids): + self._oprot.writeMessageBegin('stopDownloads', TMessageType.CALL, self._seqid) + args = stopDownloads_args() + args.fids = fids args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getInteractionTask(self, ): + def recv_stopDownloads(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getInteractionTask_result() + result = stopDownloads_result() result.read(self._iprot) self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getInteractionTask failed: unknown result"); + return - def setInteractionResult(self, iid, result): - """ - Parameters: - - iid - - result - """ - self.send_setInteractionResult(iid, result) - self.recv_setInteractionResult() + def stopAllDownloads(self, ): + self.send_stopAllDownloads() + self.recv_stopAllDownloads() - def send_setInteractionResult(self, iid, result): - self._oprot.writeMessageBegin('setInteractionResult', TMessageType.CALL, self._seqid) - args = setInteractionResult_args() - args.iid = iid - args.result = result + def send_stopAllDownloads(self, ): + self._oprot.writeMessageBegin('stopAllDownloads', TMessageType.CALL, self._seqid) + args = stopAllDownloads_args() args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_setInteractionResult(self, ): + def recv_stopAllDownloads(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = setInteractionResult_result() + result = stopAllDownloads_result() result.read(self._iprot) self._iprot.readMessageEnd() return - def generateDownloadLink(self, fid, timeout): + def isInteractionWaiting(self, mode): """ Parameters: - - fid - - timeout + - mode """ - self.send_generateDownloadLink(fid, timeout) - return self.recv_generateDownloadLink() + self.send_isInteractionWaiting(mode) + return self.recv_isInteractionWaiting() - def send_generateDownloadLink(self, fid, timeout): - self._oprot.writeMessageBegin('generateDownloadLink', TMessageType.CALL, self._seqid) - args = generateDownloadLink_args() - args.fid = fid - args.timeout = timeout + def send_isInteractionWaiting(self, mode): + self._oprot.writeMessageBegin('isInteractionWaiting', TMessageType.CALL, self._seqid) + args = isInteractionWaiting_args() + args.mode = mode args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_generateDownloadLink(self, ): + def recv_isInteractionWaiting(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = generateDownloadLink_result() + result = isInteractionWaiting_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "generateDownloadLink failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "isInteractionWaiting failed: unknown result"); - def getNotifications(self, ): - self.send_getNotifications() - return self.recv_getNotifications() + def getInteractionTask(self, mode): + """ + Parameters: + - mode + """ + self.send_getInteractionTask(mode) + return self.recv_getInteractionTask() - def send_getNotifications(self, ): - self._oprot.writeMessageBegin('getNotifications', TMessageType.CALL, self._seqid) - args = getNotifications_args() + def send_getInteractionTask(self, mode): + self._oprot.writeMessageBegin('getInteractionTask', TMessageType.CALL, self._seqid) + args = getInteractionTask_args() + args.mode = mode args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getNotifications(self, ): + def recv_getInteractionTask(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getNotifications_result() + result = getInteractionTask_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getNotifications failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "getInteractionTask failed: unknown result"); - def getAddonHandler(self, ): - self.send_getAddonHandler() - return self.recv_getAddonHandler() + def setInteractionResult(self, iid, result): + """ + Parameters: + - iid + - result + """ + self.send_setInteractionResult(iid, result) + self.recv_setInteractionResult() - def send_getAddonHandler(self, ): - self._oprot.writeMessageBegin('getAddonHandler', TMessageType.CALL, self._seqid) - args = getAddonHandler_args() + def send_setInteractionResult(self, iid, result): + self._oprot.writeMessageBegin('setInteractionResult', TMessageType.CALL, self._seqid) + args = setInteractionResult_args() + args.iid = iid + args.result = result args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getAddonHandler(self, ): + def recv_setInteractionResult(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getAddonHandler_result() + result = setInteractionResult_result() result.read(self._iprot) self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getAddonHandler failed: unknown result"); + return - def callAddonHandler(self, plugin, func, pid_or_fid): + def generateDownloadLink(self, fid, timeout): """ Parameters: - - plugin - - func - - pid_or_fid + - fid + - timeout """ - self.send_callAddonHandler(plugin, func, pid_or_fid) - self.recv_callAddonHandler() + self.send_generateDownloadLink(fid, timeout) + return self.recv_generateDownloadLink() - def send_callAddonHandler(self, plugin, func, pid_or_fid): - self._oprot.writeMessageBegin('callAddonHandler', TMessageType.CALL, self._seqid) - args = callAddonHandler_args() - args.plugin = plugin - args.func = func - args.pid_or_fid = pid_or_fid + def send_generateDownloadLink(self, fid, timeout): + self._oprot.writeMessageBegin('generateDownloadLink', TMessageType.CALL, self._seqid) + args = generateDownloadLink_args() + args.fid = fid + args.timeout = timeout args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_callAddonHandler(self, ): + def recv_generateDownloadLink(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = callAddonHandler_result() + result = generateDownloadLink_result() result.read(self._iprot) self._iprot.readMessageEnd() - return + if result.success is not None: + return result.success + raise TApplicationException(TApplicationException.MISSING_RESULT, "generateDownloadLink failed: unknown result"); + + def getNotifications(self, ): + self.send_getNotifications() + return self.recv_getNotifications() + + def send_getNotifications(self, ): + self._oprot.writeMessageBegin('getNotifications', TMessageType.CALL, self._seqid) + args = getNotifications_args() + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_getNotifications(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = getNotifications_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + if result.success is not None: + return result.success + raise TApplicationException(TApplicationException.MISSING_RESULT, "getNotifications failed: unknown result"); def getEvents(self, uuid): """ @@ -3006,155 +2952,189 @@ class Client(Iface): return result.success raise TApplicationException(TApplicationException.MISSING_RESULT, "setPassword failed: unknown result"); - def getServices(self, ): - self.send_getServices() - return self.recv_getServices() + def getAllInfo(self, ): + self.send_getAllInfo() + return self.recv_getAllInfo() - def send_getServices(self, ): - self._oprot.writeMessageBegin('getServices', TMessageType.CALL, self._seqid) - args = getServices_args() + def send_getAllInfo(self, ): + self._oprot.writeMessageBegin('getAllInfo', TMessageType.CALL, self._seqid) + args = getAllInfo_args() args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getServices(self, ): + def recv_getAllInfo(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getServices_result() + result = getAllInfo_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getServices failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "getAllInfo failed: unknown result"); - def hasService(self, plugin, func): + def getInfoByPlugin(self, plugin): """ Parameters: - plugin - - func """ - self.send_hasService(plugin, func) - return self.recv_hasService() + self.send_getInfoByPlugin(plugin) + return self.recv_getInfoByPlugin() - def send_hasService(self, plugin, func): - self._oprot.writeMessageBegin('hasService', TMessageType.CALL, self._seqid) - args = hasService_args() + def send_getInfoByPlugin(self, plugin): + self._oprot.writeMessageBegin('getInfoByPlugin', TMessageType.CALL, self._seqid) + args = getInfoByPlugin_args() args.plugin = plugin - args.func = func args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_hasService(self, ): + def recv_getInfoByPlugin(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = getInfoByPlugin_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + if result.success is not None: + return result.success + raise TApplicationException(TApplicationException.MISSING_RESULT, "getInfoByPlugin failed: unknown result"); + + def getAddonHandler(self, ): + self.send_getAddonHandler() + return self.recv_getAddonHandler() + + def send_getAddonHandler(self, ): + self._oprot.writeMessageBegin('getAddonHandler', TMessageType.CALL, self._seqid) + args = getAddonHandler_args() + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_getAddonHandler(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = hasService_result() + result = getAddonHandler_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "hasService failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "getAddonHandler failed: unknown result"); - def call(self, plugin, func, arguments): + def hasAddonHandler(self, plugin, func): """ Parameters: - plugin - func - - arguments """ - self.send_call(plugin, func, arguments) - return self.recv_call() + self.send_hasAddonHandler(plugin, func) + return self.recv_hasAddonHandler() - def send_call(self, plugin, func, arguments): - self._oprot.writeMessageBegin('call', TMessageType.CALL, self._seqid) - args = call_args() + def send_hasAddonHandler(self, plugin, func): + self._oprot.writeMessageBegin('hasAddonHandler', TMessageType.CALL, self._seqid) + args = hasAddonHandler_args() args.plugin = plugin args.func = func - args.arguments = arguments args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_call(self, ): + def recv_hasAddonHandler(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = call_result() + result = hasAddonHandler_result() result.read(self._iprot) self._iprot.readMessageEnd() if result.success is not None: return result.success - if result.ex is not None: - raise result.ex - if result.e is not None: - raise result.e - raise TApplicationException(TApplicationException.MISSING_RESULT, "call failed: unknown result"); + raise TApplicationException(TApplicationException.MISSING_RESULT, "hasAddonHandler failed: unknown result"); - def getAllInfo(self, ): - self.send_getAllInfo() - return self.recv_getAllInfo() + def callAddon(self, plugin, func, arguments): + """ + Parameters: + - plugin + - func + - arguments + """ + self.send_callAddon(plugin, func, arguments) + self.recv_callAddon() - def send_getAllInfo(self, ): - self._oprot.writeMessageBegin('getAllInfo', TMessageType.CALL, self._seqid) - args = getAllInfo_args() + def send_callAddon(self, plugin, func, arguments): + self._oprot.writeMessageBegin('callAddon', TMessageType.CALL, self._seqid) + args = callAddon_args() + args.plugin = plugin + args.func = func + args.arguments = arguments args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getAllInfo(self, ): + def recv_callAddon(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getAllInfo_result() + result = callAddon_result() result.read(self._iprot) self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getAllInfo failed: unknown result"); + if result.e is not None: + raise result.e + if result.ex is not None: + raise result.ex + return - def getInfoByPlugin(self, plugin): + def callAddonHandler(self, plugin, func, pid_or_fid): """ Parameters: - plugin + - func + - pid_or_fid """ - self.send_getInfoByPlugin(plugin) - return self.recv_getInfoByPlugin() + self.send_callAddonHandler(plugin, func, pid_or_fid) + self.recv_callAddonHandler() - def send_getInfoByPlugin(self, plugin): - self._oprot.writeMessageBegin('getInfoByPlugin', TMessageType.CALL, self._seqid) - args = getInfoByPlugin_args() + def send_callAddonHandler(self, plugin, func, pid_or_fid): + self._oprot.writeMessageBegin('callAddonHandler', TMessageType.CALL, self._seqid) + args = callAddonHandler_args() args.plugin = plugin + args.func = func + args.pid_or_fid = pid_or_fid args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() - def recv_getInfoByPlugin(self, ): + def recv_callAddonHandler(self, ): (fname, mtype, rseqid) = self._iprot.readMessageBegin() if mtype == TMessageType.EXCEPTION: x = TApplicationException() x.read(self._iprot) self._iprot.readMessageEnd() raise x - result = getInfoByPlugin_result() + result = callAddonHandler_result() result.read(self._iprot) self._iprot.readMessageEnd() - if result.success is not None: - return result.success - raise TApplicationException(TApplicationException.MISSING_RESULT, "getInfoByPlugin failed: unknown result"); + if result.e is not None: + raise result.e + if result.ex is not None: + raise result.ex + return class Processor(Iface, TProcessor): @@ -3174,7 +3154,6 @@ class Processor(Iface, TProcessor): self._processMap["isTimeReconnect"] = Processor.process_isTimeReconnect self._processMap["toggleReconnect"] = Processor.process_toggleReconnect self._processMap["scanDownloadFolder"] = Processor.process_scanDownloadFolder - self._processMap["getProgressInfo"] = Processor.process_getProgressInfo self._processMap["getConfigValue"] = Processor.process_getConfigValue self._processMap["setConfigValue"] = Processor.process_setConfigValue self._processMap["getConfig"] = Processor.process_getConfig @@ -3188,13 +3167,13 @@ class Processor(Iface, TProcessor): self._processMap["pollResults"] = Processor.process_pollResults self._processMap["generatePackages"] = Processor.process_generatePackages self._processMap["generateAndAddPackages"] = Processor.process_generateAndAddPackages - self._processMap["autoAddLinks"] = Processor.process_autoAddLinks self._processMap["createPackage"] = Processor.process_createPackage self._processMap["addPackage"] = Processor.process_addPackage self._processMap["addPackageP"] = Processor.process_addPackageP self._processMap["addPackageChild"] = Processor.process_addPackageChild self._processMap["uploadContainer"] = Processor.process_uploadContainer self._processMap["addLinks"] = Processor.process_addLinks + self._processMap["addLocalFile"] = Processor.process_addLocalFile self._processMap["deleteFiles"] = Processor.process_deleteFiles self._processMap["deletePackages"] = Processor.process_deletePackages self._processMap["getCollector"] = Processor.process_getCollector @@ -3214,8 +3193,6 @@ class Processor(Iface, TProcessor): self._processMap["restartPackage"] = Processor.process_restartPackage self._processMap["restartFile"] = Processor.process_restartFile self._processMap["recheckPackage"] = Processor.process_recheckPackage - self._processMap["stopDownloads"] = Processor.process_stopDownloads - self._processMap["stopAllDownloads"] = Processor.process_stopAllDownloads self._processMap["restartFailed"] = Processor.process_restartFailed self._processMap["setFilePaused"] = Processor.process_setFilePaused self._processMap["setPackagePaused"] = Processor.process_setPackagePaused @@ -3225,13 +3202,14 @@ class Processor(Iface, TProcessor): self._processMap["moveFiles"] = Processor.process_moveFiles self._processMap["orderPackage"] = Processor.process_orderPackage self._processMap["orderFiles"] = Processor.process_orderFiles + self._processMap["getProgressInfo"] = Processor.process_getProgressInfo + self._processMap["stopDownloads"] = Processor.process_stopDownloads + self._processMap["stopAllDownloads"] = Processor.process_stopAllDownloads self._processMap["isInteractionWaiting"] = Processor.process_isInteractionWaiting self._processMap["getInteractionTask"] = Processor.process_getInteractionTask self._processMap["setInteractionResult"] = Processor.process_setInteractionResult self._processMap["generateDownloadLink"] = Processor.process_generateDownloadLink self._processMap["getNotifications"] = Processor.process_getNotifications - self._processMap["getAddonHandler"] = Processor.process_getAddonHandler - self._processMap["callAddonHandler"] = Processor.process_callAddonHandler self._processMap["getEvents"] = Processor.process_getEvents self._processMap["getAccounts"] = Processor.process_getAccounts self._processMap["getAccountTypes"] = Processor.process_getAccountTypes @@ -3244,11 +3222,12 @@ class Processor(Iface, TProcessor): self._processMap["updateUserData"] = Processor.process_updateUserData self._processMap["removeUser"] = Processor.process_removeUser self._processMap["setPassword"] = Processor.process_setPassword - self._processMap["getServices"] = Processor.process_getServices - self._processMap["hasService"] = Processor.process_hasService - self._processMap["call"] = Processor.process_call self._processMap["getAllInfo"] = Processor.process_getAllInfo self._processMap["getInfoByPlugin"] = Processor.process_getInfoByPlugin + self._processMap["getAddonHandler"] = Processor.process_getAddonHandler + self._processMap["hasAddonHandler"] = Processor.process_hasAddonHandler + self._processMap["callAddon"] = Processor.process_callAddon + self._processMap["callAddonHandler"] = Processor.process_callAddonHandler def process(self, iprot, oprot): (name, type, seqid) = iprot.readMessageBegin() @@ -3408,17 +3387,6 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() - def process_getProgressInfo(self, seqid, iprot, oprot): - args = getProgressInfo_args() - args.read(iprot) - iprot.readMessageEnd() - result = getProgressInfo_result() - result.success = self._handler.getProgressInfo() - oprot.writeMessageBegin("getProgressInfo", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - def process_getConfigValue(self, seqid, iprot, oprot): args = getConfigValue_args() args.read(iprot) @@ -3562,17 +3530,6 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() - def process_autoAddLinks(self, seqid, iprot, oprot): - args = autoAddLinks_args() - args.read(iprot) - iprot.readMessageEnd() - result = autoAddLinks_result() - result.success = self._handler.autoAddLinks(args.links) - oprot.writeMessageBegin("autoAddLinks", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - def process_createPackage(self, seqid, iprot, oprot): args = createPackage_args() args.read(iprot) @@ -3642,6 +3599,20 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() + def process_addLocalFile(self, seqid, iprot, oprot): + args = addLocalFile_args() + args.read(iprot) + iprot.readMessageEnd() + result = addLocalFile_result() + try: + self._handler.addLocalFile(args.pid, args.name, args.path) + except PackageDoesNotExists, e: + result.e = e + oprot.writeMessageBegin("addLocalFile", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + def process_deleteFiles(self, seqid, iprot, oprot): args = deleteFiles_args() args.read(iprot) @@ -3850,31 +3821,9 @@ class Processor(Iface, TProcessor): args = recheckPackage_args() args.read(iprot) iprot.readMessageEnd() - result = recheckPackage_result() - self._handler.recheckPackage(args.pid) - oprot.writeMessageBegin("recheckPackage", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - - def process_stopDownloads(self, seqid, iprot, oprot): - args = stopDownloads_args() - args.read(iprot) - iprot.readMessageEnd() - result = stopDownloads_result() - self._handler.stopDownloads(args.fids) - oprot.writeMessageBegin("stopDownloads", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - - def process_stopAllDownloads(self, seqid, iprot, oprot): - args = stopAllDownloads_args() - args.read(iprot) - iprot.readMessageEnd() - result = stopAllDownloads_result() - self._handler.stopAllDownloads() - oprot.writeMessageBegin("stopAllDownloads", TMessageType.REPLY, seqid) + result = recheckPackage_result() + self._handler.recheckPackage(args.pid) + oprot.writeMessageBegin("recheckPackage", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() @@ -3996,6 +3945,39 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() + def process_getProgressInfo(self, seqid, iprot, oprot): + args = getProgressInfo_args() + args.read(iprot) + iprot.readMessageEnd() + result = getProgressInfo_result() + result.success = self._handler.getProgressInfo() + oprot.writeMessageBegin("getProgressInfo", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_stopDownloads(self, seqid, iprot, oprot): + args = stopDownloads_args() + args.read(iprot) + iprot.readMessageEnd() + result = stopDownloads_result() + self._handler.stopDownloads(args.fids) + oprot.writeMessageBegin("stopDownloads", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_stopAllDownloads(self, seqid, iprot, oprot): + args = stopAllDownloads_args() + args.read(iprot) + iprot.readMessageEnd() + result = stopAllDownloads_result() + self._handler.stopAllDownloads() + oprot.writeMessageBegin("stopAllDownloads", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + def process_isInteractionWaiting(self, seqid, iprot, oprot): args = isInteractionWaiting_args() args.read(iprot) @@ -4051,28 +4033,6 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() - def process_getAddonHandler(self, seqid, iprot, oprot): - args = getAddonHandler_args() - args.read(iprot) - iprot.readMessageEnd() - result = getAddonHandler_result() - result.success = self._handler.getAddonHandler() - oprot.writeMessageBegin("getAddonHandler", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - - def process_callAddonHandler(self, seqid, iprot, oprot): - args = callAddonHandler_args() - args.read(iprot) - iprot.readMessageEnd() - result = callAddonHandler_result() - self._handler.callAddonHandler(args.plugin, args.func, args.pid_or_fid) - oprot.writeMessageBegin("callAddonHandler", TMessageType.REPLY, seqid) - result.write(oprot) - oprot.writeMessageEnd() - oprot.trans.flush() - def process_getEvents(self, seqid, iprot, oprot): args = getEvents_args() args.read(iprot) @@ -4205,62 +4165,78 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() - def process_getServices(self, seqid, iprot, oprot): - args = getServices_args() + def process_getAllInfo(self, seqid, iprot, oprot): + args = getAllInfo_args() + args.read(iprot) + iprot.readMessageEnd() + result = getAllInfo_result() + result.success = self._handler.getAllInfo() + oprot.writeMessageBegin("getAllInfo", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_getInfoByPlugin(self, seqid, iprot, oprot): + args = getInfoByPlugin_args() args.read(iprot) iprot.readMessageEnd() - result = getServices_result() - result.success = self._handler.getServices() - oprot.writeMessageBegin("getServices", TMessageType.REPLY, seqid) + result = getInfoByPlugin_result() + result.success = self._handler.getInfoByPlugin(args.plugin) + oprot.writeMessageBegin("getInfoByPlugin", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() - def process_hasService(self, seqid, iprot, oprot): - args = hasService_args() + def process_getAddonHandler(self, seqid, iprot, oprot): + args = getAddonHandler_args() args.read(iprot) iprot.readMessageEnd() - result = hasService_result() - result.success = self._handler.hasService(args.plugin, args.func) - oprot.writeMessageBegin("hasService", TMessageType.REPLY, seqid) + result = getAddonHandler_result() + result.success = self._handler.getAddonHandler() + oprot.writeMessageBegin("getAddonHandler", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() - def process_call(self, seqid, iprot, oprot): - args = call_args() + def process_hasAddonHandler(self, seqid, iprot, oprot): + args = hasAddonHandler_args() args.read(iprot) iprot.readMessageEnd() - result = call_result() - try: - result.success = self._handler.call(args.plugin, args.func, args.arguments) - except ServiceDoesNotExists, ex: - result.ex = ex - except ServiceException, e: - result.e = e - oprot.writeMessageBegin("call", TMessageType.REPLY, seqid) + result = hasAddonHandler_result() + result.success = self._handler.hasAddonHandler(args.plugin, args.func) + oprot.writeMessageBegin("hasAddonHandler", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() - def process_getAllInfo(self, seqid, iprot, oprot): - args = getAllInfo_args() + def process_callAddon(self, seqid, iprot, oprot): + args = callAddon_args() args.read(iprot) iprot.readMessageEnd() - result = getAllInfo_result() - result.success = self._handler.getAllInfo() - oprot.writeMessageBegin("getAllInfo", TMessageType.REPLY, seqid) + result = callAddon_result() + try: + self._handler.callAddon(args.plugin, args.func, args.arguments) + except ServiceDoesNotExists, e: + result.e = e + except ServiceException, ex: + result.ex = ex + oprot.writeMessageBegin("callAddon", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() - def process_getInfoByPlugin(self, seqid, iprot, oprot): - args = getInfoByPlugin_args() + def process_callAddonHandler(self, seqid, iprot, oprot): + args = callAddonHandler_args() args.read(iprot) iprot.readMessageEnd() - result = getInfoByPlugin_result() - result.success = self._handler.getInfoByPlugin(args.plugin) - oprot.writeMessageBegin("getInfoByPlugin", TMessageType.REPLY, seqid) + result = callAddonHandler_result() + try: + self._handler.callAddonHandler(args.plugin, args.func, args.pid_or_fid) + except ServiceDoesNotExists, e: + result.e = e + except ServiceException, ex: + result.ex = ex + oprot.writeMessageBegin("callAddonHandler", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() oprot.trans.flush() @@ -4584,33 +4560,6 @@ class scanDownloadFolder_result(TBase): ) -class getProgressInfo_args(TBase): - - __slots__ = [ - ] - - thrift_spec = ( - ) - - -class getProgressInfo_result(TBase): - """ - Attributes: - - success - """ - - __slots__ = [ - 'success', - ] - - thrift_spec = ( - (0, TType.LIST, 'success', (TType.STRUCT,(ProgressInfo, ProgressInfo.thrift_spec)), None, ), # 0 - ) - - def __init__(self, success=None,): - self.success = success - - class getConfigValue_args(TBase): """ Attributes: @@ -5090,43 +5039,6 @@ class generateAndAddPackages_result(TBase): self.success = success -class autoAddLinks_args(TBase): - """ - Attributes: - - links - """ - - __slots__ = [ - 'links', - ] - - thrift_spec = ( - None, # 0 - (1, TType.LIST, 'links', (TType.STRING,None), None, ), # 1 - ) - - def __init__(self, links=None,): - self.links = links - - -class autoAddLinks_result(TBase): - """ - Attributes: - - success - """ - - __slots__ = [ - 'success', - ] - - thrift_spec = ( - (0, TType.LIST, 'success', (TType.I32,None), None, ), # 0 - ) - - def __init__(self, success=None,): - self.success = success - - class createPackage_args(TBase): """ Attributes: @@ -5418,6 +5330,52 @@ class addLinks_result(TBase): self.e = e +class addLocalFile_args(TBase): + """ + Attributes: + - pid + - name + - path + """ + + __slots__ = [ + 'pid', + 'name', + 'path', + ] + + thrift_spec = ( + None, # 0 + (1, TType.I32, 'pid', None, None, ), # 1 + (2, TType.STRING, 'name', None, None, ), # 2 + (3, TType.STRING, 'path', None, None, ), # 3 + ) + + def __init__(self, pid=None, name=None, path=None,): + self.pid = pid + self.name = name + self.path = path + + +class addLocalFile_result(TBase): + """ + Attributes: + - e + """ + + __slots__ = [ + 'e', + ] + + thrift_spec = ( + None, # 0 + (1, TType.STRUCT, 'e', (PackageDoesNotExists, PackageDoesNotExists.thrift_spec), None, ), # 1 + ) + + def __init__(self, e=None,): + self.e = e + + class deleteFiles_args(TBase): """ Attributes: @@ -6013,65 +5971,19 @@ class recheckPackage_args(TBase): """ __slots__ = [ - 'pid', - ] - - thrift_spec = ( - None, # 0 - (1, TType.I32, 'pid', None, None, ), # 1 - ) - - def __init__(self, pid=None,): - self.pid = pid - - -class recheckPackage_result(TBase): - - __slots__ = [ - ] - - thrift_spec = ( - ) - - -class stopDownloads_args(TBase): - """ - Attributes: - - fids - """ - - __slots__ = [ - 'fids', - ] - - thrift_spec = ( - None, # 0 - (1, TType.LIST, 'fids', (TType.I32,None), None, ), # 1 - ) - - def __init__(self, fids=None,): - self.fids = fids - - -class stopDownloads_result(TBase): - - __slots__ = [ - ] - - thrift_spec = ( - ) - - -class stopAllDownloads_args(TBase): - - __slots__ = [ + 'pid', ] thrift_spec = ( + None, # 0 + (1, TType.I32, 'pid', None, None, ), # 1 ) + def __init__(self, pid=None,): + self.pid = pid + -class stopAllDownloads_result(TBase): +class recheckPackage_result(TBase): __slots__ = [ ] @@ -6427,6 +6339,79 @@ class orderFiles_result(TBase): ) +class getProgressInfo_args(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class getProgressInfo_result(TBase): + """ + Attributes: + - success + """ + + __slots__ = [ + 'success', + ] + + thrift_spec = ( + (0, TType.LIST, 'success', (TType.STRUCT,(ProgressInfo, ProgressInfo.thrift_spec)), None, ), # 0 + ) + + def __init__(self, success=None,): + self.success = success + + +class stopDownloads_args(TBase): + """ + Attributes: + - fids + """ + + __slots__ = [ + 'fids', + ] + + thrift_spec = ( + None, # 0 + (1, TType.LIST, 'fids', (TType.I32,None), None, ), # 1 + ) + + def __init__(self, fids=None,): + self.fids = fids + + +class stopDownloads_result(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class stopAllDownloads_args(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class stopAllDownloads_result(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + class isInteractionWaiting_args(TBase): """ Attributes: @@ -6601,69 +6586,6 @@ class getNotifications_result(TBase): self.success = success -class getAddonHandler_args(TBase): - - __slots__ = [ - ] - - thrift_spec = ( - ) - - -class getAddonHandler_result(TBase): - """ - Attributes: - - success - """ - - __slots__ = [ - 'success', - ] - - thrift_spec = ( - (0, TType.MAP, 'success', (TType.STRING,None,TType.LIST,(TType.STRUCT,(AddonService, AddonService.thrift_spec))), None, ), # 0 - ) - - def __init__(self, success=None,): - self.success = success - - -class callAddonHandler_args(TBase): - """ - Attributes: - - plugin - - func - - pid_or_fid - """ - - __slots__ = [ - 'plugin', - 'func', - 'pid_or_fid', - ] - - thrift_spec = ( - None, # 0 - (1, TType.STRING, 'plugin', None, None, ), # 1 - (2, TType.STRING, 'func', None, None, ), # 2 - (3, TType.I32, 'pid_or_fid', None, None, ), # 3 - ) - - def __init__(self, plugin=None, func=None, pid_or_fid=None,): - self.plugin = plugin - self.func = func - self.pid_or_fid = pid_or_fid - - -class callAddonHandler_result(TBase): - - __slots__ = [ - ] - - thrift_spec = ( - ) - - class getEvents_args(TBase): """ Attributes: @@ -7074,7 +6996,7 @@ class setPassword_result(TBase): self.success = success -class getServices_args(TBase): +class getAllInfo_args(TBase): __slots__ = [ ] @@ -7083,7 +7005,7 @@ class getServices_args(TBase): ) -class getServices_result(TBase): +class getAllInfo_result(TBase): """ Attributes: - success @@ -7094,37 +7016,33 @@ class getServices_result(TBase): ] thrift_spec = ( - (0, TType.MAP, 'success', (TType.STRING,None,TType.LIST,(TType.STRUCT,(AddonService, AddonService.thrift_spec))), None, ), # 0 + (0, TType.MAP, 'success', (TType.STRING,None,TType.LIST,(TType.STRUCT,(AddonInfo, AddonInfo.thrift_spec))), None, ), # 0 ) def __init__(self, success=None,): self.success = success -class hasService_args(TBase): +class getInfoByPlugin_args(TBase): """ Attributes: - plugin - - func """ __slots__ = [ 'plugin', - 'func', ] thrift_spec = ( None, # 0 (1, TType.STRING, 'plugin', None, None, ), # 1 - (2, TType.STRING, 'func', None, None, ), # 2 ) - def __init__(self, plugin=None, func=None,): + def __init__(self, plugin=None,): self.plugin = plugin - self.func = func -class hasService_result(TBase): +class getInfoByPlugin_result(TBase): """ Attributes: - success @@ -7135,126 +7053,177 @@ class hasService_result(TBase): ] thrift_spec = ( - (0, TType.BOOL, 'success', None, None, ), # 0 + (0, TType.LIST, 'success', (TType.STRUCT,(AddonInfo, AddonInfo.thrift_spec)), None, ), # 0 + ) + + def __init__(self, success=None,): + self.success = success + + +class getAddonHandler_args(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class getAddonHandler_result(TBase): + """ + Attributes: + - success + """ + + __slots__ = [ + 'success', + ] + + thrift_spec = ( + (0, TType.MAP, 'success', (TType.STRING,None,TType.LIST,(TType.STRUCT,(AddonService, AddonService.thrift_spec))), None, ), # 0 ) def __init__(self, success=None,): self.success = success -class call_args(TBase): +class hasAddonHandler_args(TBase): """ Attributes: - plugin - func - - arguments """ __slots__ = [ 'plugin', 'func', - 'arguments', ] thrift_spec = ( None, # 0 (1, TType.STRING, 'plugin', None, None, ), # 1 (2, TType.STRING, 'func', None, None, ), # 2 - (3, TType.STRING, 'arguments', None, None, ), # 3 ) - def __init__(self, plugin=None, func=None, arguments=None,): + def __init__(self, plugin=None, func=None,): self.plugin = plugin self.func = func - self.arguments = arguments -class call_result(TBase): +class hasAddonHandler_result(TBase): """ Attributes: - success - - ex - - e """ __slots__ = [ 'success', - 'ex', - 'e', ] thrift_spec = ( - (0, TType.STRING, 'success', None, None, ), # 0 - (1, TType.STRUCT, 'ex', (ServiceDoesNotExists, ServiceDoesNotExists.thrift_spec), None, ), # 1 - (2, TType.STRUCT, 'e', (ServiceException, ServiceException.thrift_spec), None, ), # 2 + (0, TType.BOOL, 'success', None, None, ), # 0 ) - def __init__(self, success=None, ex=None, e=None,): + def __init__(self, success=None,): self.success = success - self.ex = ex - self.e = e -class getAllInfo_args(TBase): +class callAddon_args(TBase): + """ + Attributes: + - plugin + - func + - arguments + """ __slots__ = [ + 'plugin', + 'func', + 'arguments', ] thrift_spec = ( + None, # 0 + (1, TType.STRING, 'plugin', None, None, ), # 1 + (2, TType.STRING, 'func', None, None, ), # 2 + (3, TType.LIST, 'arguments', (TType.STRING,None), None, ), # 3 ) + def __init__(self, plugin=None, func=None, arguments=None,): + self.plugin = plugin + self.func = func + self.arguments = arguments + -class getAllInfo_result(TBase): +class callAddon_result(TBase): """ Attributes: - - success + - e + - ex """ __slots__ = [ - 'success', + 'e', + 'ex', ] thrift_spec = ( - (0, TType.MAP, 'success', (TType.STRING,None,TType.LIST,(TType.STRUCT,(AddonInfo, AddonInfo.thrift_spec))), None, ), # 0 + None, # 0 + (1, TType.STRUCT, 'e', (ServiceDoesNotExists, ServiceDoesNotExists.thrift_spec), None, ), # 1 + (2, TType.STRUCT, 'ex', (ServiceException, ServiceException.thrift_spec), None, ), # 2 ) - def __init__(self, success=None,): - self.success = success + def __init__(self, e=None, ex=None,): + self.e = e + self.ex = ex -class getInfoByPlugin_args(TBase): +class callAddonHandler_args(TBase): """ Attributes: - plugin + - func + - pid_or_fid """ __slots__ = [ 'plugin', + 'func', + 'pid_or_fid', ] thrift_spec = ( None, # 0 (1, TType.STRING, 'plugin', None, None, ), # 1 + (2, TType.STRING, 'func', None, None, ), # 2 + (3, TType.I32, 'pid_or_fid', None, None, ), # 3 ) - def __init__(self, plugin=None,): + def __init__(self, plugin=None, func=None, pid_or_fid=None,): self.plugin = plugin + self.func = func + self.pid_or_fid = pid_or_fid -class getInfoByPlugin_result(TBase): +class callAddonHandler_result(TBase): """ Attributes: - - success + - e + - ex """ __slots__ = [ - 'success', + 'e', + 'ex', ] thrift_spec = ( - (0, TType.LIST, 'success', (TType.STRUCT,(AddonInfo, AddonInfo.thrift_spec)), None, ), # 0 + None, # 0 + (1, TType.STRUCT, 'e', (ServiceDoesNotExists, ServiceDoesNotExists.thrift_spec), None, ), # 1 + (2, TType.STRUCT, 'ex', (ServiceException, ServiceException.thrift_spec), None, ), # 2 ) - def __init__(self, success=None,): - self.success = success + def __init__(self, e=None, ex=None,): + self.e = e + self.ex = ex diff --git a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py b/module/remote/thriftbackend/thriftgen/pyload/ttypes.py index d170f4688..3e4cce276 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py +++ b/module/remote/thriftbackend/thriftgen/pyload/ttypes.py @@ -195,38 +195,35 @@ class Permission(TBase): All = 0 Add = 1 Delete = 2 - Status = 4 - List = 16 - Modify = 32 - Download = 64 - Accounts = 128 - Interaction = 256 - Addons = 512 + Modify = 4 + Status = 8 + Download = 16 + Accounts = 32 + Interaction = 64 + Addons = 128 _VALUES_TO_NAMES = { 0: "All", 1: "Add", 2: "Delete", - 4: "Status", - 16: "List", - 32: "Modify", - 64: "Download", - 128: "Accounts", - 256: "Interaction", - 512: "Addons", + 4: "Modify", + 8: "Status", + 16: "Download", + 32: "Accounts", + 64: "Interaction", + 128: "Addons", } _NAMES_TO_VALUES = { "All": 0, "Add": 1, "Delete": 2, - "Status": 4, - "List": 16, - "Modify": 32, - "Download": 64, - "Accounts": 128, - "Interaction": 256, - "Addons": 512, + "Modify": 4, + "Status": 8, + "Download": 16, + "Accounts": 32, + "Interaction": 64, + "Addons": 128, } class Role(TBase): @@ -675,6 +672,37 @@ class InteractionTask(TBase): self.plugin = plugin +class AddonService(TBase): + """ + Attributes: + - func_name + - description + - arguments + - media + """ + + __slots__ = [ + 'func_name', + 'description', + 'arguments', + 'media', + ] + + thrift_spec = ( + None, # 0 + (1, TType.STRING, 'func_name', None, None, ), # 1 + (2, TType.STRING, 'description', None, None, ), # 2 + (3, TType.LIST, 'arguments', (TType.STRING,None), None, ), # 3 + (4, TType.I16, 'media', None, None, ), # 4 + ) + + def __init__(self, func_name=None, description=None, arguments=None, media=None,): + self.func_name = func_name + self.description = description + self.arguments = arguments + self.media = media + + class AddonInfo(TBase): """ Attributes: @@ -818,6 +846,8 @@ class UserData(TBase): - folder - traffic - dllimit + - dlquota + - hddquota - user - templateName """ @@ -831,6 +861,8 @@ class UserData(TBase): 'folder', 'traffic', 'dllimit', + 'dlquota', + 'hddquota', 'user', 'templateName', ] @@ -845,11 +877,13 @@ class UserData(TBase): (6, TType.STRING, 'folder', None, None, ), # 6 (7, TType.I64, 'traffic', None, None, ), # 7 (8, TType.I16, 'dllimit', None, None, ), # 8 - (9, TType.I32, 'user', None, None, ), # 9 - (10, TType.STRING, 'templateName', None, None, ), # 10 + (9, TType.STRING, 'dlquota', None, None, ), # 9 + (10, TType.I64, 'hddquota', None, None, ), # 10 + (11, TType.I32, 'user', None, None, ), # 11 + (12, TType.STRING, 'templateName', None, None, ), # 12 ) - def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, dllimit=None, user=None, templateName=None,): + def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, dllimit=None, dlquota=None, hddquota=None, user=None, templateName=None,): self.uid = uid self.name = name self.email = email @@ -858,6 +892,8 @@ class UserData(TBase): self.folder = folder self.traffic = traffic self.dllimit = dllimit + self.dlquota = dlquota + self.hddquota = hddquota self.user = user self.templateName = templateName @@ -921,37 +957,6 @@ class AccountInfo(TBase): self.options = options -class AddonService(TBase): - """ - Attributes: - - func_name - - description - - media - - package - """ - - __slots__ = [ - 'func_name', - 'description', - 'media', - 'package', - ] - - thrift_spec = ( - None, # 0 - (1, TType.STRING, 'func_name', None, None, ), # 1 - (2, TType.STRING, 'description', None, None, ), # 2 - (3, TType.I16, 'media', None, None, ), # 3 - (4, TType.BOOL, 'package', None, None, ), # 4 - ) - - def __init__(self, func_name=None, description=None, media=None, package=None,): - self.func_name = func_name - self.description = description - self.media = media - self.package = package - - class OnlineCheck(TBase): """ Attributes: diff --git a/module/threads/ThreadManager.py b/module/threads/ThreadManager.py index c3da13430..e3407aac3 100644 --- a/module/threads/ThreadManager.py +++ b/module/threads/ThreadManager.py @@ -1,22 +1,20 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - @author: RaNaN -""" +############################################################################### +# 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 os.path import exists, join import re @@ -28,7 +26,7 @@ from random import choice import pycurl -from module.PyFile import PyFile +from module.datatypes import PyFile from module.network.RequestFactory import getURL from module.utils import lock, uniqify from module.utils.fs import free_space diff --git a/module/utils/__init__.py b/module/utils/__init__.py index 37e65c738..28d734bb5 100644 --- a/module/utils/__init__.py +++ b/module/utils/__init__.py @@ -212,6 +212,15 @@ def from_string(value, typ=None): else: return value +def get_index(l, value): + """ .index method that also works on tuple and python 2.5 """ + for pos, t in enumerate(l): + if t == value: + return pos + + # Matches behavior of list.index + raise ValueError("list.index(x): x not in list") + def html_unescape(text): """Removes HTML or XML character references and entities from a text string""" -- cgit v1.2.3