diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-01-03 17:14:02 +0100 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-01-03 17:14:02 +0100 |
commit | a6b5a69612f4dd744be20c326152a9d892150f98 (patch) | |
tree | f3a221e2c8e1b805b5b83c0136978b9fb36eae59 /module | |
parent | little cleanup, improved handling of custom exceptions via api (diff) | |
download | pyload-a6b5a69612f4dd744be20c326152a9d892150f98.tar.xz |
seperate api into several components
Diffstat (limited to 'module')
-rw-r--r-- | module/Api.py | 236 | ||||
-rw-r--r-- | module/api/ApiComponent.py | 12 | ||||
-rw-r--r-- | module/api/ConfigApi.py | 104 | ||||
-rw-r--r-- | module/api/CoreApi.py | 121 | ||||
-rw-r--r-- | module/api/__init__.py | 1 | ||||
-rw-r--r-- | module/config/ConfigManager.py | 6 | ||||
-rw-r--r-- | module/datatypes/User.py | 7 |
7 files changed, 274 insertions, 213 deletions
diff --git a/module/Api.py b/module/Api.py index dc500dabe..9a92da0ec 100644 --- a/module/Api.py +++ b/module/Api.py @@ -20,7 +20,7 @@ import re from os.path import join, isabs from itertools import chain from functools import partial -from new import code +from types import MethodType, CodeType from dis import opmap from remote.ttypes import * @@ -70,7 +70,7 @@ class UserContext(object): # load argument instead of global new_code = new_code.replace(chr(opmap['LOAD_GLOBAL']) + chr(i), chr(opmap['LOAD_FAST']) + chr(fc.co_argcount)) - new_fc = code(fc.co_argcount + 1, fc.co_nlocals + 1, fc.co_stacksize, fc.co_flags, new_code, fc.co_consts, + new_fc = CodeType(fc.co_argcount + 1, fc.co_nlocals + 1, fc.co_stacksize, fc.co_flags, new_code, fc.co_consts, new_names, new_varnames, fc.co_filename, fc.co_name, fc.co_firstlineno, fc.co_lnotab, fc.co_freevars, fc.co_cellvars) @@ -138,11 +138,37 @@ class Api(Iface): """ EXTERNAL = Iface # let the json api know which methods are external + EXTEND = False # only extendable when set too true def __init__(self, core): self.core = core self.user_apis = {} + @classmethod + def initComponents(cls): + # Allow extending the api + # This prevents unintentionally registering of the components, + # but will only work once when they are imported + cls.EXTEND = True + # Import all Api modules, they register themselves. + from module.api import * + # they will vanish from the namespace afterwards + + + @classmethod + def extend(cls, api): + """Takes all params from api and extends cls with it. + api class can be removed afterwards + + :param api: Class with methods to extend + """ + if cls.EXTEND: + for name, func in api.__dict__.iteritems(): + if name.startswith("_"): continue + setattr(cls, name, MethodType(func, None, cls)) + + return cls.EXTEND + def withUserContext(self, uid): """ Returns a proxy version of the api, to call method in user context @@ -162,210 +188,6 @@ class Api(Iface): return self.user_apis[uid] - ########################## - # Server Status - ########################## - - @RequirePerm(Permission.All) - def getServerVersion(self): - """pyLoad Core version """ - return self.core.version - - @RequirePerm(Permission.All) - def getWSAddress(self): - """Gets and address for the websocket based on configuration""" - # TODO - - @RequirePerm(Permission.All) - def getServerStatus(self): - """Some general information about the current status of pyLoad. - - :return: `ServerStatus` - """ - serverStatus = ServerStatus(self.core.files.getQueueCount(), self.core.files.getFileCount(), 0, - not self.core.threadManager.pause and self.isTimeDownload(), self.core.threadManager.pause, - self.core.config['reconnect']['activated'] and self.isTimeReconnect()) - - for pyfile in self.core.threadManager.getActiveDownloads(): - serverStatus.speed += pyfile.getSpeed() #bytes/s - - return serverStatus - - @RequirePerm(Permission.All) - def getProgressInfo(self): - """ Status of all currently running tasks - - :return: list of `ProgressInfo` - """ - pass - - def pauseServer(self): - """Pause server: It won't start any new downloads, but nothing gets aborted.""" - self.core.threadManager.pause = True - - def unpauseServer(self): - """Unpause server: New Downloads will be started.""" - self.core.threadManager.pause = False - - def togglePause(self): - """Toggle pause state. - - :return: new pause state - """ - self.core.threadManager.pause ^= True - return self.core.threadManager.pause - - def toggleReconnect(self): - """Toggle reconnect activation. - - :return: new reconnect state - """ - self.core.config["reconnect"]["activated"] ^= True - return self.core.config["reconnect"]["activated"] - - def freeSpace(self): - """Available free space at download directory in bytes""" - return free_space(self.core.config["general"]["download_folder"]) - - - def quit(self): - """Clean way to quit pyLoad""" - self.core.do_kill = True - - def restart(self): - """Restart pyload core""" - self.core.do_restart = True - - def getLog(self, offset=0): - """Returns most recent log entries. - - :param offset: line offset - :return: List of log entries - """ - filename = join(self.core.config['log']['log_folder'], 'log.txt') - try: - fh = open(filename, "r") - lines = fh.readlines() - fh.close() - if offset >= len(lines): - return [] - return lines[offset:] - except: - return ['No log available'] - - @RequirePerm(Permission.All) - def isTimeDownload(self): - """Checks if pyload will start new downloads according to time in config. - - :return: bool - """ - start = self.core.config['downloadTime']['start'].split(":") - end = self.core.config['downloadTime']['end'].split(":") - return compare_time(start, end) - - @RequirePerm(Permission.All) - def isTimeReconnect(self): - """Checks if pyload will try to make a reconnect - - :return: bool - """ - start = self.core.config['reconnect']['startTime'].split(":") - end = self.core.config['reconnect']['endTime'].split(":") - return compare_time(start, end) and self.core.config["reconnect"]["activated"] - - ########################## - # Configuration - ########################## - - def getConfigValue(self, section, option): - """Retrieve config value. - - :param section: name of category, or plugin - :param option: config option - :return: config value as string - """ - value = self.core.config.get(section, option) - return to_string(value) - - def setConfigValue(self, section, option, value): - """Set new config value. - - :param section: - :param option: - :param value: new config value - """ - if option in ("limit_speed", "max_speed"): #not so nice to update the limit - self.core.requestFactory.updateBucket() - - self.core.config.set(section, option, value) - - def getConfig(self): - """Retrieves complete config of core. - - :rtype : ConfigHolder - :return: dict with section mapped to config - """ - # TODO - return dict([(section, ConfigHolder(section, data.name, data.description, data.long_desc, [ - ConfigItem(option, d.name, d.description, d.type, to_string(d.default), - to_string(self.core.config.get(section, option))) for - option, d in data.config.iteritems()])) for - section, data in self.core.config.getBaseSections()]) - - - def getConfigRef(self): - """Config instance, not for RPC""" - return self.core.config - - def getGlobalPlugins(self): - """All global plugins/addons, only admin can use this - - :return: list of `ConfigInfo` - """ - pass - - @UserContext - @RequirePerm(Permission.Plugins) - def getUserPlugins(self): - """List of plugins every user can configure for himself - - :return: list of `ConfigInfo` - """ - pass - - @UserContext - @RequirePerm(Permission.Plugins) - def configurePlugin(self, plugin): - """Get complete config options for an plugin - - :param plugin: Name of the plugin to configure - :return: :class:`ConfigHolder` - """ - - pass - - @UserContext - @RequirePerm(Permission.Plugins) - def saveConfig(self, config): - """Used to save a configuration, core config can only be saved by admins - - :param config: :class:`ConfigHolder - """ - pass - - @UserContext - @RequirePerm(Permission.Plugins) - def deleteConfig(self, plugin): - """Deletes modified config - - :param plugin: plugin name - :return: - """ - pass - - @RequirePerm(Permission.Plugins) - def setConfigHandler(self, plugin, iid, value): - pass ########################## # Download Preparing @@ -1054,4 +876,4 @@ class Api(Iface): :param plugin: pluginname :return: dict of attr names mapped to value {"name": value} """ - return self.core.addonManager.getInfo(plugin) + return self.core.addonManager.getInfo(plugin)
\ No newline at end of file diff --git a/module/api/ApiComponent.py b/module/api/ApiComponent.py new file mode 100644 index 000000000..2b09d05a3 --- /dev/null +++ b/module/api/ApiComponent.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +class ApiComponent: + + def __init__(self, core): + # Only for auto completion, this class can not be instantiated + from pyload import Core + assert isinstance(core, Core) + self.core = core + # No instantiating! + raise Exception()
\ No newline at end of file diff --git a/module/api/ConfigApi.py b/module/api/ConfigApi.py new file mode 100644 index 000000000..f3f2e6950 --- /dev/null +++ b/module/api/ConfigApi.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from module.Api import Api, UserContext, RequirePerm, Permission, ConfigHolder, ConfigItem +from module.utils import to_string + +from ApiComponent import ApiComponent + +class ConfigApi(ApiComponent): + """ Everything related to configuration """ + + def getConfigValue(self, section, option): + """Retrieve config value. + + :param section: name of category, or plugin + :param option: config option + :rtype: str + :return: config value as string + """ + value = self.core.config.get(section, option) + return to_string(value) + + def setConfigValue(self, section, option, value): + """Set new config value. + + :param section: + :param option: + :param value: new config value + """ + if option in ("limit_speed", "max_speed"): #not so nice to update the limit + self.core.requestFactory.updateBucket() + + self.core.config.set(section, option, value) + + def getConfig(self): + """Retrieves complete config of core. + + :rtype: ConfigHolder + :return: dict with section mapped to config + """ + # TODO + return dict([(section, ConfigHolder(section, data.name, data.description, data.long_desc, [ + ConfigItem(option, d.name, d.description, d.type, to_string(d.default), + to_string(self.core.config.get(section, option))) for + option, d in data.config.iteritems()])) for + section, data in self.core.config.getBaseSections()]) + + + def getConfigRef(self): + """Config instance, not for RPC""" + return self.core.config + + def getGlobalPlugins(self): + """All global plugins/addons, only admin can use this + + :return: list of `ConfigInfo` + """ + pass + + @UserContext + @RequirePerm(Permission.Plugins) + def getUserPlugins(self): + """List of plugins every user can configure for himself + + :return: list of `ConfigInfo` + """ + pass + + @UserContext + @RequirePerm(Permission.Plugins) + def configurePlugin(self, plugin): + """Get complete config options for an plugin + + :param plugin: Name of the plugin to configure + :return: :class:`ConfigHolder` + """ + + pass + + @UserContext + @RequirePerm(Permission.Plugins) + def saveConfig(self, config): + """Used to save a configuration, core config can only be saved by admins + + :param config: :class:`ConfigHolder + """ + pass + + @UserContext + @RequirePerm(Permission.Plugins) + def deleteConfig(self, plugin): + """Deletes modified config + + :param plugin: plugin name + :return: + """ + pass + + @RequirePerm(Permission.Plugins) + def setConfigHandler(self, plugin, iid, value): + pass + +if Api.extend(ConfigApi): + del ConfigApi
\ No newline at end of file diff --git a/module/api/CoreApi.py b/module/api/CoreApi.py new file mode 100644 index 000000000..4de8c1f96 --- /dev/null +++ b/module/api/CoreApi.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from module.Api import Api, RequirePerm, Permission, ServerStatus +from module.utils.fs import join, free_space +from module.utils import compare_time + +from ApiComponent import ApiComponent + +class CoreApi(ApiComponent): + """ This module provides methods for general interaction with the core, like status or progress retrieval """ + + @RequirePerm(Permission.All) + def getServerVersion(self): + """pyLoad Core version """ + return self.core.version + + @RequirePerm(Permission.All) + def getWSAddress(self): + """Gets and address for the websocket based on configuration""" + # TODO + + @RequirePerm(Permission.All) + def getServerStatus(self): + """Some general information about the current status of pyLoad. + + :return: `ServerStatus` + """ + serverStatus = ServerStatus(self.core.files.getQueueCount(), self.core.files.getFileCount(), 0, + not self.core.threadManager.pause and self.isTimeDownload(), self.core.threadManager.pause, + self.core.config['reconnect']['activated'] and self.isTimeReconnect()) + + for pyfile in self.core.threadManager.getActiveDownloads(): + serverStatus.speed += pyfile.getSpeed() #bytes/s + + return serverStatus + + @RequirePerm(Permission.All) + def getProgressInfo(self): + """ Status of all currently running tasks + + :rtype: list of :class:`ProgressInfo` + """ + pass + + def pauseServer(self): + """Pause server: It won't start any new downloads, but nothing gets aborted.""" + self.core.threadManager.pause = True + + def unpauseServer(self): + """Unpause server: New Downloads will be started.""" + self.core.threadManager.pause = False + + def togglePause(self): + """Toggle pause state. + + :return: new pause state + """ + self.core.threadManager.pause ^= True + return self.core.threadManager.pause + + def toggleReconnect(self): + """Toggle reconnect activation. + + :return: new reconnect state + """ + self.core.config["reconnect"]["activated"] ^= True + return self.core.config["reconnect"]["activated"] + + def freeSpace(self): + """Available free space at download directory in bytes""" + return free_space(self.core.config["general"]["download_folder"]) + + + def quit(self): + """Clean way to quit pyLoad""" + self.core.do_kill = True + + def restart(self): + """Restart pyload core""" + self.core.do_restart = True + + def getLog(self, offset=0): + """Returns most recent log entries. + + :param offset: line offset + :return: List of log entries + """ + filename = join(self.core.config['log']['log_folder'], 'log.txt') + try: + fh = open(filename, "r") + lines = fh.readlines() + fh.close() + if offset >= len(lines): + return [] + return lines[offset:] + except: + return ['No log available'] + + @RequirePerm(Permission.All) + def isTimeDownload(self): + """Checks if pyload will start new downloads according to time in config. + + :return: bool + """ + start = self.core.config['downloadTime']['start'].split(":") + end = self.core.config['downloadTime']['end'].split(":") + return compare_time(start, end) + + @RequirePerm(Permission.All) + def isTimeReconnect(self): + """Checks if pyload will try to make a reconnect + + :return: bool + """ + start = self.core.config['reconnect']['startTime'].split(":") + end = self.core.config['reconnect']['endTime'].split(":") + return compare_time(start, end) and self.core.config["reconnect"]["activated"] + +if Api.extend(CoreApi): + del CoreApi
\ No newline at end of file diff --git a/module/api/__init__.py b/module/api/__init__.py new file mode 100644 index 000000000..f7ceb6183 --- /dev/null +++ b/module/api/__init__.py @@ -0,0 +1 @@ +__all__ = ["CoreApi", "ConfigApi"]
\ No newline at end of file diff --git a/module/config/ConfigManager.py b/module/config/ConfigManager.py index 872ce2e00..4898b0c66 100644 --- a/module/config/ConfigManager.py +++ b/module/config/ConfigManager.py @@ -57,7 +57,7 @@ class ConfigManager(ConfigParser): else: # We need the id and not the instance # Will be None for admin user and so the same as internal access - user = user.handle if user else None + user = user.primary if user else None try: # Check if this config exists # Configs without meta data can not be loaded! @@ -87,7 +87,7 @@ class ConfigManager(ConfigParser): changed = self.parser.set(section, option, value, sync) else: # associated id - user = user.handle if user else None + user = user.primary if user else None data = self.config[section].config[option] value = from_string(value, data.type) old_value = self.get(section, option) @@ -107,7 +107,7 @@ class ConfigManager(ConfigParser): def delete(self, section, user=False): """ Deletes values saved in db and cached values for given user, NOT meta data Does not trigger an error when nothing was deleted. """ - user = user.handle if user else None + user = user.primary if user else None if (user, section) in self.values: del self.values[user, section] diff --git a/module/datatypes/User.py b/module/datatypes/User.py index 3832653c7..bdf52d860 100644 --- a/module/datatypes/User.py +++ b/module/datatypes/User.py @@ -55,8 +55,9 @@ class User(UserData): return self.hasRole(Role.Admin) @property - def handle(self): - """ Internal user handle used for most operations (secondary share handle with primary user) """ + def primary(self): + """ Primary user id, Internal user handle used for most operations + Secondary user account share id with primary user. Only Admins have no primary id. """ if self.hasRole(Role.Admin): return None - return self.user if self.user else self.uid + return self.user if self.user else self.uid
\ No newline at end of file |