summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/Api.py236
-rw-r--r--module/api/ApiComponent.py12
-rw-r--r--module/api/ConfigApi.py104
-rw-r--r--module/api/CoreApi.py121
-rw-r--r--module/api/__init__.py1
-rw-r--r--module/config/ConfigManager.py6
-rw-r--r--module/datatypes/User.py7
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