summaryrefslogtreecommitdiffstats
path: root/module/config
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-01-02 18:11:31 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-01-02 18:11:31 +0100
commit6b20f5f6c063e4e6c94d719b607ad5a028b8beee (patch)
treea8c3dfa9962aa819507870553700a35b7dcc4c74 /module/config
parentRemove '/' from filename to avoid filepath exception (diff)
downloadpyload-6b20f5f6c063e4e6c94d719b607ad5a028b8beee.tar.xz
new configManager for multi user configs
Diffstat (limited to 'module/config')
-rw-r--r--module/config/ConfigManager.py118
-rw-r--r--module/config/ConfigParser.py130
-rw-r--r--module/config/default.py30
3 files changed, 167 insertions, 111 deletions
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)
+ ])