#!/usr/bin/env python # -*- coding: utf-8 -*- from new_collections import OrderedDict from pyload.Api import InvalidConfigSection from pyload.utils import json from ConfigParser import ConfigParser from convert import to_input, from_string 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 user is None: 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 try: # Check if this config exists # Configs without meta data can not be loaded! data = self.config[section].config[option] return self.loadValues(user, section)[option] except KeyError: pass # Returns default value later return self.config[section].config[option].input.default_value 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() return self.values[user, section] @convertKeyError def set(self, section, option, value, sync=True, user=None): """ set config value """ changed = False if section in self.parser and user is None: changed = self.parser.set(section, option, value, sync) else: data = self.config[section].config[option] value = from_string(value, data.input.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 if sync: self.saveValues(user, section) if changed: self.core.evm.dispatchEvent("config:changed", section, option, value) return changed def saveValues(self, user, section): if section in self.parser and user is None: self.save() elif (user, section) in self.values: self.db.saveConfig(section, json.dumps(self.values[user, section]), user) def delete(self, section, user=None): """ Deletes values saved in db and cached values for given user, NOT meta data Does not trigger an error when nothing was deleted. """ if (user, section) in self.values: del self.values[user, section] self.db.deleteConfig(section, user) self.core.evm.dispatchEvent("config:deleted", section, user) def iterCoreSections(self): return self.parser.iterSections() def iterSections(self, user=None): """ Yields: section, metadata, values """ values = self.db.loadConfigsForUser(user) # Every section needs to be json decoded for section, data in values.items(): try: values[section] = json.loads(data) if data else {} except ValueError: values[section] = {} self.core.print_exc() for name, config in self.config.iteritems(): yield name, config, values[name] if name in values else {} def getSection(self, section, user=None): if section in self.parser and user is None: return self.parser.getSection(section) values = self.loadValues(user, section) return self.config.get(section), values