diff options
Diffstat (limited to 'module')
| -rw-r--r-- | module/AddonManager.py | 9 | ||||
| -rw-r--r-- | module/Api.py | 4 | ||||
| -rw-r--r-- | module/PluginManager.py | 3 | ||||
| -rw-r--r-- | module/config/ConfigManager.py | 118 | ||||
| -rw-r--r-- | module/config/ConfigParser.py | 130 | ||||
| -rw-r--r-- | module/config/default.py | 30 | ||||
| -rw-r--r-- | module/database/ConfigDatabase.py | 5 | ||||
| -rw-r--r-- | module/datatypes/User.py | 5 | ||||
| -rw-r--r-- | module/remote/pyload.thrift | 4 | ||||
| -rw-r--r-- | module/remote/ttypes.py | 6 | ||||
| -rw-r--r-- | module/remote/ttypes_debug.py | 1 | 
11 files changed, 191 insertions, 124 deletions
| diff --git a/module/AddonManager.py b/module/AddonManager.py index 4283b4652..ad6daaf83 100644 --- a/module/AddonManager.py +++ b/module/AddonManager.py @@ -45,9 +45,6 @@ class AddonManager:          self.lock = RLock()          self.createIndex() -        #registering callback for config event -        self.config.changeCB = MethodType(self.dispatchEvent, "configChanged", basestring) -          # manage addons an config change          self.addEvent("configChanged", self.manageAddons) @@ -64,8 +61,7 @@ class AddonManager:              return func(*args)          except Exception, e:              addon.logError(_("Error when executing %s" % f), e) -            if self.core.debug: -                print_exc() +            self.core.print_exc()      def addRPC(self, plugin, func, doc):          doc = doc.strip() if doc else "" @@ -114,8 +110,7 @@ class AddonManager:              except:                  self.log.warning(_("Failed activating %(name)s") % {"name": pluginname}) -                if self.core.debug: -                    print_exc() +                self.core.print_exc()          self.log.info(_("Activated addons: %s") % ", ".join(sorted(active)))          self.log.info(_("Deactivate addons: %s") % ", ".join(sorted(deactive))) diff --git a/module/Api.py b/module/Api.py index 0b777a659..fb3c59483 100644 --- a/module/Api.py +++ b/module/Api.py @@ -302,7 +302,8 @@ class Api(Iface):      def getConfig(self):          """Retrieves complete config of core. -        :return: map of `ConfigHolder` +        :rtype : ConfigHolder +        :return: dict with section mapped to config          """          # TODO          return dict([(section, ConfigHolder(section, data.name, data.description, data.long_desc, [ @@ -765,6 +766,7 @@ class Api(Iface):          p = self.core.files.getPackage(pid)          if not p: raise PackageDoesNotExists(pid) +        #TODO: fix          for key, value in data.iteritems():              if key == "id": continue              setattr(p, key, value) diff --git a/module/PluginManager.py b/module/PluginManager.py index 2bd438c37..31ad38625 100644 --- a/module/PluginManager.py +++ b/module/PluginManager.py @@ -62,7 +62,8 @@ class PluginManager:          self.history = [] # match history to speedup parsing (type, name)          self.createIndex() -        self.core.config.parseValues(self.core.config.PLUGIN) +        # TODO, replacement for this? +        #self.core.config.parseValues(self.core.config.PLUGIN)          #register for import addon          sys.meta_path.append(self) diff --git a/module/config/ConfigManager.py b/module/config/ConfigManager.py new file mode 100644 index 000000000..3ee66bc85 --- /dev/null +++ b/module/config/ConfigManager.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from new_collections import OrderedDict + +from module.Api import InvalidConfigSection +from module.common.json_layer import json +from module.utils import from_string + +from ConfigParser import ConfigParser + + +def convertKeyError(func): +    """ converts KeyError into InvalidConfigSection """ + +    def conv(*args, **kwargs): +        try: +            return func(*args, **kwargs) +        except KeyError: +            raise InvalidConfigSection(args[1]) + +    return conv + + +class ConfigManager(ConfigParser): +    """ Manages the core config and configs for addons and single user. +        Has similar interface to ConfigParser. """ + +    def __init__(self, core, parser): +        # No __init__ call to super class is needed! + +        self.core = core +        self.db = core.db +        # The config parser, holding the core config +        self.parser = parser + +        # similar to parser, separated meta data and values +        self.config = OrderedDict() + +        # Value cache for multiple user configs +        # Values are populated from db on first access +        # Entries are saved as (user, section) keys +        self.values = {} +        # TODO: similar to a cache, could be deleted periodically + +    def save(self): +        self.parser.save() + +    @convertKeyError +    def get(self, section, option, user=None): +        """get config value, core config only available for admins. +        if user is not valid default value will be returned""" + +        # Core config loaded from parser, when no user is given or he is admin +        if section in self.parser and (not user or(user and user.isAdmin())): +            return self.parser.get(section, option) +        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 +            try: +                # Check if this config exists +                # Configs without meta data can not be loaded! +                data = self.config[section].config[option] +                self.loadValues(user, section) +                return self.values[user, section][option] +            except KeyError: +                pass # Returns default value later + +        return self.config[section].config[option].default + +    def loadValues(self, user, section): +        if (user, section) not in self.values: +            conf = self.db.loadConfig(section, user) +            try: +                self.values[user, section] = json.loads(conf) if conf else {} +            except ValueError: # Something did go wrong when parsing +                self.values[user, section] = {} +                self.core.print_exc() + +    @convertKeyError +    def set(self, section, option, value, sync=True, user=None): +        """ set config value  """ + +        changed = False +        if section in self.parser and (not user or (user and user.isAdmin())): +            changed = self.parser.set(section, option, value, sync) +        else: +            # associated id +            user = user.handle if user else None +            data = self.config[section].config[option] +            value = from_string(value, data.type) +            old_value = self.get(section, option) + +            # Values will always be saved to db, sync is ignored +            if value != old_value: +                changed = True +                self.values[user, section][option] = value +                self.saveValues(user, section) + +        if changed: self.core.evm.dispatchEvent("configChanged", value) +        return changed + +    def saveValues(self, user, section): +        self.db.saveConfig(section, json.dumps(self.values[user, section]), user) + +    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 +        if (user, section) in self.values: +            del self.values[user, section] + +        self.db.deleteConfig(section, user) + + +    def iterSections(self): +        pass
\ No newline at end of file diff --git a/module/config/ConfigParser.py b/module/config/ConfigParser.py index 3cad67bc2..135e84bbc 100644 --- a/module/config/ConfigParser.py +++ b/module/config/ConfigParser.py @@ -17,25 +17,20 @@ ConfigData = namedtuple("ConfigData", "name type description default")  class ConfigParser:      """ -    Holds and manages the configuration + meta data for core and every user. +    Holds and manages the configuration + meta data for config read from file.      """      CONFIG = "pyload.conf" -    PLUGIN = "plugin.conf" -    def __init__(self): -        """Constructor""" +    def __init__(self, config=None): -        # core config sections from pyload -        self.baseSections = [] +        if config: self.CONFIG = config          # Meta data information          self.config = OrderedDict()          # The actual config values          self.values = {} -        self.changeCB = None # callback when config value was changed -          self.checkVersion()          self.loadDefault() @@ -50,22 +45,21 @@ class ConfigParser:          # workaround conflict, with GUI (which also accesses the config) so try read in 3 times          for i in range(0, 3):              try: -                for conf in (self.CONFIG, self.PLUGIN): -                    if exists(conf): -                        f = open(conf, "rb") -                        v = f.readline() -                        f.close() -                        v = v[v.find(":") + 1:].strip() - -                        if not v or int(v) < CONF_VERSION: -                            f = open(conf, "wb") -                            f.write("version: " + str(CONF_VERSION)) -                            f.close() -                            print "Old version of %s deleted" % conf -                    else: -                        f = open(conf, "wb") -                        f.write("version:" + str(CONF_VERSION)) +                if exists(self.CONFIG): +                    f = open(self.CONFIG, "rb") +                    v = f.readline() +                    f.close() +                    v = v[v.find(":") + 1:].strip() + +                    if not v or int(v) < CONF_VERSION: +                        f = open(self.CONFIG, "wb") +                        f.write("version: " + str(CONF_VERSION))                          f.close() +                        print "Old version of %s deleted" % self.CONFIG +                else: +                    f = open(self.CONFIG, "wb") +                    f.write("version:" + str(CONF_VERSION)) +                    f.close()              except Exception, ex:                  e = ex @@ -112,19 +106,13 @@ class ConfigParser:      def save(self):          """saves config to filename""" -        # separate pyload and plugin conf          configs = [] -        for c in (self.CONFIG, self.PLUGIN): -            f = open(c, "wb") -            configs.append(f) -            chmod(c, 0600) -            f.write("version: %i\n\n" % CONF_VERSION) - +        f = open(self.CONFIG, "wb") +        configs.append(f) +        chmod(self.CONFIG, 0600) +        f.write("version: %i\n\n" % CONF_VERSION) -        # write on 2 files          for section, data in self.config.iteritems(): -            f = configs[0] if section in self.baseSections else configs[1] -              f.write("[%s]\n" % section)              for option, data in data.config.iteritems(): @@ -136,17 +124,21 @@ class ConfigParser:              f.write("\n") -        [f.close() for f in configs] +        f.close()      def __getitem__(self, section):          """provides dictionary like access: c['section']['option']"""          return Section(self, section) +    def __contains__(self, section): +        """ checks if parser contains section """ +        return section in self.config +      def get(self, section, option): -        """get value""" -        if option in self.values[section]: +        """get value or default""" +        try:              return self.values[section][option] -        else: +        except KeyError:              return self.config[section].config[option].default      def set(self, section, option, value, sync=True): @@ -154,45 +146,27 @@ class ConfigParser:          data = self.config[section].config[option]          value = from_string(value, data.type) +        old_value = self.get(section, option) -        # only save when different to default values -        if value != data.default or (option in self.values[section] and value != self.values[section][option]): +        # only save when different values +        if value != old_value: +            if section not in self.values: self.values[section] = {}              self.values[section][option] = value              if sync: -                if self.changeCB: self.changeCB(section, option, value)                  self.save() +            return True -    def getPlugin(self, *args): -        """gets a value for a plugin""" -        ret = self.get(*args) -        print "Deprecated method getPlugin%s -> %s" % (str(args), ret) -        return ret - -    def setPlugin(self, *args): -        """sets a value for a plugin""" -        print "Deprecated method setPlugin%s" % str(args) -        self.set(*args) +        return False      def getMetaData(self, section, option):          """ get all config data for an option """          return self.config[section].config[option] -    def getBaseSections(self): -        for section, data in self.config.iteritems(): -            if section in self.baseSections: -                yield section, data -        return - -    def getPluginSections(self): -        for section, data in self.config.iteritems(): -            if section not in self.baseSections: -                yield section, data -        return +    def iterSections(self): +        return self.config.iteritems() -    def addConfigSection(self, section, name, desc, long_desc, config, base=False): +    def addConfigSection(self, section, name, desc, long_desc, config):          """Adds a section to the config. `config` is a list of config tuples as used in plugin api defined as: -        Either (name, type, verbose_name, default_value) or -                (name, type, verbose_name, short_description, default_value)          The order of the config elements is preserved with OrderedDict          """          d = OrderedDict() @@ -200,23 +174,15 @@ class ConfigParser:          for entry in config:              if len(entry) == 5:                  conf_name, type, conf_desc, conf_verbose, default = entry -            else: # config options without tooltip / description +            else: # config options without description                  conf_name, type, conf_desc, default = entry                  conf_verbose = ""              d[conf_name] = ConfigData(gettext(conf_desc), type, gettext(conf_verbose), from_string(default, type)) -        if base: -            if section not in self.baseSections: self.baseSections.append(section) -        elif section in self.baseSections: -            return # would overwrite base section -          data = SectionTuple(gettext(name), gettext(desc), gettext(long_desc), d)          self.config[section] = data -        if section not in self.values: -            self.values[section] = {} -  class Section:      """provides dictionary like access for configparser""" @@ -232,21 +198,3 @@ class Section:      def __setitem__(self, item, value):          """setitem"""          self.parser.set(self.section, item, value) - - -if __name__ == "__main__": -    pypath = "" - -    from time import time - -    a = time() - -    c = ConfigParser() - -    b = time() - -    print "sec", b - a - -    print c.config - -    c.saveConfig(c.config, "user.conf") diff --git a/module/config/default.py b/module/config/default.py index a9fad675c..e55ba6593 100644 --- a/module/config/default.py +++ b/module/config/default.py @@ -16,8 +16,7 @@ def make_config(config):              ("activated", "bool", _("Activated"), _("Tooltip"), True),              ("port", "int", _("Port"), _("Tooltip"), 7227),              ("listenaddr", "ip", _("Adress"), _("Tooltip"), "0.0.0.0"), -        ], -        True) +        ])      config.addConfigSection("log", _("Log"), _("Description"), _("Long description"),          [ @@ -26,8 +25,7 @@ def make_config(config):              ("file_log", "bool", _("File Log"), _("Tooltip"), True),              ("log_count", "int", _("Count"), _("Tooltip"), 5),              ("log_rotate", "bool", _("Log Rotate"), _("Tooltip"), True), -        ], -        True) +        ])      config.addConfigSection("permission", _("Permissions"), _("Description"), _("Long description"),          [ @@ -39,8 +37,7 @@ def make_config(config):              ("change_group", "bool", _("Change group of running process"), _("Tooltip"), False),              ("folder", "str", _("Folder Permission mode"), _("Tooltip"), "0755"),              ("change_user", "bool", _("Change user of running process"), _("Tooltip"), False), -        ], -        True) +        ])      config.addConfigSection("general", _("General"), _("Description"), _("Long description"),          [ @@ -51,16 +48,14 @@ def make_config(config):              ("debug_mode", "bool", _("Debug Mode"), _("Tooltip"), False),              ("min_free_space", "int", _("Min Free Space (MB)"), _("Tooltip"), 200),              ("renice", "int", _("CPU Priority"), _("Tooltip"), 0), -        ], -        True) +        ])      config.addConfigSection("ssl", _("SSL"), _("Description"), _("Long description"),          [              ("cert", "file", _("SSL Certificate"), _("Tooltip"), "ssl.crt"),              ("activated", "bool", _("Activated"), _("Tooltip"), False),              ("key", "file", _("SSL Key"), _("Tooltip"), "ssl.key"), -        ], -        True) +        ])      config.addConfigSection("webinterface", _("Webinterface"), _("Description"), _("Long description"),          [ @@ -71,8 +66,7 @@ def make_config(config):              ("host", "ip", _("IP"), _("Tooltip"), "0.0.0.0"),              ("https", "bool", _("Use HTTPS"), _("Tooltip"), False),              ("port", "int", _("Port"), _("Tooltip"), 8001), -        ], -        True) +        ])      config.addConfigSection("proxy", _("Proxy"), _("Description"), _("Long description"),          [ @@ -82,8 +76,7 @@ def make_config(config):              ("password", "password", _("Password"), _("Tooltip"), ""),              ("type", "http;socks4;socks5", _("Protocol"), _("Tooltip"), "http"),              ("port", "int", _("Port"), _("Tooltip"), 7070), -        ], -        True) +        ])      config.addConfigSection("reconnect", _("Reconnect"), _("Description"), _("Long description"),          [ @@ -91,8 +84,7 @@ def make_config(config):              ("activated", "bool", _("Use Reconnect"), _("Tooltip"), False),              ("method", "str", _("Method"), _("Tooltip"), "./reconnect.sh"),              ("startTime", "time", _("Start"), _("Tooltip"), "0:00"), -        ], -        True) +        ])      config.addConfigSection("download", _("Download"), _("Description"), _("Long description"),          [ @@ -104,12 +96,10 @@ def make_config(config):              ("ipv6", "bool", _("Allow IPv6"), _("Tooltip"), False),              ("chunks", "int", _("Max connections for one download"), _("Tooltip"), 3),              ("restart_failed", "bool", _("Restart failed downloads on startup"), _("Tooltip"), False), -        ], -        True) +        ])      config.addConfigSection("downloadTime", _("Download Time"), _("Description"), _("Long description"),          [              ("start", "time", _("Start"), _("Tooltip"), "0:00"),              ("end", "time", _("End"), _("Tooltip"), "0:00"), -        ], -        True) +        ]) diff --git a/module/database/ConfigDatabase.py b/module/database/ConfigDatabase.py index 198ae0173..7dd5909b8 100644 --- a/module/database/ConfigDatabase.py +++ b/module/database/ConfigDatabase.py @@ -16,11 +16,12 @@ class ConfigMethods(DatabaseMethods):      @queue      def loadConfig(self, plugin, user=None):          if user is None: -            self.c.execute('SELECT config FROM settings WHERE plugin=?', (plugin, )) +            self.c.execute('SELECT config FROM settings WHERE plugin=? AND user=-1', (plugin, ))          else:              self.c.execute('SELECT config FROM settings WHERE plugin=? AND user=?', (plugin, user)) -        return self.c.fetchone()[0] +        r = self.c.fetchone() +        return r[0] if r else ""      @async      def deleteConfig(self, plugin, user=None): diff --git a/module/datatypes/User.py b/module/datatypes/User.py index d48111182..3832653c7 100644 --- a/module/datatypes/User.py +++ b/module/datatypes/User.py @@ -28,12 +28,13 @@ class User(UserData):          return User(api, 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, api,  *args): -        UserData.__init__(self, *args) +    def __init__(self, api,  *args, **kwargs): +        UserData.__init__(self, *args, **kwargs)          self.api = api      def toUserData(self): +        # TODO          return UserData()      def hasPermission(self, perms): diff --git a/module/remote/pyload.thrift b/module/remote/pyload.thrift index 183fd3af8..47c371904 100644 --- a/module/remote/pyload.thrift +++ b/module/remote/pyload.thrift @@ -315,6 +315,10 @@ exception ServiceException {    1: string msg  } +exception InvalidConfigSection { +  1: string section +} +  exception Unauthorized {  } diff --git a/module/remote/ttypes.py b/module/remote/ttypes.py index eb990f2e8..d661c684a 100644 --- a/module/remote/ttypes.py +++ b/module/remote/ttypes.py @@ -220,6 +220,12 @@ class InteractionTask(BaseObject):  		self.description = description  		self.plugin = plugin +class InvalidConfigSection(Exception): +	__slots__ = ['section'] + +	def __init__(self, section=None): +		self.section = section +  class LinkStatus(BaseObject):  	__slots__ = ['url', 'name', 'plugin', 'size', 'status', 'packagename'] diff --git a/module/remote/ttypes_debug.py b/module/remote/ttypes_debug.py index 807a8451b..1e04624d9 100644 --- a/module/remote/ttypes_debug.py +++ b/module/remote/ttypes_debug.py @@ -18,6 +18,7 @@ classes = {  	'FileDoesNotExists' : [int],  	'FileInfo' : [int, basestring, int, int, int, int, int, int, int, (None, DownloadInfo)],  	'InteractionTask' : [int, int, (list, basestring), int, (None, basestring), basestring, basestring, basestring], +	'InvalidConfigSection' : [basestring],  	'LinkStatus' : [basestring, basestring, basestring, int, int, basestring],  	'OnlineCheck' : [int, (dict, basestring, LinkStatus)],  	'PackageDoesNotExists' : [int], | 
