예제 #1
0
 def read_config_from_hd(self): 
     self._config_file.read(self._main_config_dir + '/settings.cfg')
     
     # load gui settings
     for tup, _val in self.get_gui_settings():
         option = tup[0]
         value = self.read_value_from_config_file(self.get_option(option), "general", option)
         self.set_option(option, value, init=True)
         
     # load hidden settings
     for option in self.get_hidden_settings():
         value = self.read_value_from_config_file(self.get_option(option), "general", option)
         self.set_option(option, value, init=True)
     
     # load settings that don't fit the default schema        
     self._ID = self.read_value_from_config_file(self._ID, "general", "ID")      
     self._available_db_connections = self.read_value_from_config_file(self._available_db_connections, "general", "available_db_connections")
     self._multiple_machines_allowed = self.read_value_from_config_file(self._multiple_machines_allowed , "general", "multiple_machines_allowed")
     externalRepos = self.read_value_from_config_file(None, "general", "external_plugin_repos")
     
     componentLoggingLevels = self.read_value_from_config_file(None, "general", "comp_logging_levels")
     if componentLoggingLevels:
         deserializeLoggingLevels(componentLoggingLevels)
         
     if externalRepos == None:
         if os.path.isdir(self.get_config("plugins")):
             externalRepos = [(self.get_config("plugins"), True, False)]  # active, but no auto update
         else:
             externalRepos = []
     else:
         externalRepos = json.loads(externalRepos)
         
     self._plugin_repos = PluginRepositories(self.get_resource("plugins"), externalRepos, logging=self.get_verbose())
     
     if len(self._ID)==0:
         self.generate_ID(init=True)
예제 #2
0
class lunch_settings(object):
    LUNCH_TIME_FORMAT = "%H:%M"
    LUNCH_TIME_FORMAT_QT = "HH:mm"
    _instance = None
    
    @classmethod
    def get_singleton_instance(cls):
        if cls._instance == None:
            cls._instance = cls()
        return cls._instance
        
    @classmethod
    def get_gui_settings(cls):
        return _GENERAL_SETTINGS
    
    @classmethod
    def get_hidden_settings(cls):
        return _HIDDEN_SETTINGS
    
    def __init__(self):
        self._main_config_dir = MAIN_CONFIG_DIR
        self._members_file = self.get_config("lunch_members.cfg") # DEPRECATED, use peers_file
        self._peers_file = self.get_config("lunch_peers.cfg")
        self._legacy_messages_file = self.get_config("messages")
        self._messages_file = self.get_config("messages.sqlite")
        self._log_file = self.get_config("lunchinator.log")
        self._avatar_dir = self.get_config("avatars")
        self._version = None
        self._commit_count = None
        self._main_package_path = self._findMainPackagePath()
        if self._main_package_path == None:
            raise Exception("Could not determine path to the main lunchinator package.")
        self._resources_path = self._findResourcesPath(self._main_package_path)
        if self._resources_path == None:
            raise Exception("Could not determine path to the lunchinator resource files.")
        self._load_plugins = True
        self._plugin_repos = None
        
        # configurable  
        self._lunch_trigger = u"lunch"
        self._user_name = getpass.getuser().decode() 
        self._group = u""
        self._avatar_file = u""    
        self._tcp_port = 50001
        self._default_lunch_begin = u"12:15"
        self._default_lunch_end = u"12:45"
        self._alarm_begin_time = u"11:30"
        self._alarm_end_time = u"13:00"
        self._mute_timeout = 30
        self._verbose = False
        self._logging_level = u"ERROR"
        self._log_cache_size = 100
        self._group_plugins = False
        self._default_db_connection = u"Standard"
        self._available_db_connections = [u"Standard"]  # list separated by ;; (like yapsy)
        self._proxy = u""
        self._warn_if_members_not_ready = True
        self._notification_if_everybody_ready = False
                
        """===also in config, but hidden==="""
        # ID (UUID) is generated at first startup
        self._ID = u""
        # time until unreachable peers are dropped and until incomplete HELOX calls are dropped
        # cleanUp thread runs twice in this interval
        self._peer_timeout = 60
        # cache lifetime to detect duplicate messages
        self._message_cache_timeout = 5
        # lunchinators standard UPD port 
        self._udp_port = 50000
        # size of a single UDP package (best value depends on the network)
        self._max_fragment_length = 512
        # allow multiple lunchinators with the same ID in the network (experimental)
        self._multiple_machines_allowed = []
        
        self._next_lunch_begin = None
        self._next_lunch_end = None
        
        if not os.path.exists(self._main_config_dir):
            os.makedirs(self._main_config_dir)
        if not os.path.exists(self._avatar_dir):
            os.makedirs(self._avatar_dir)
            
        self._config_file = ConfigParser.SafeConfigParser()
        self.read_config_from_hd()
        
        # insert plugin folders into path
        for aDir in self.get_plugin_dirs():
            # TODO check first!
            sys.path.insert(0, aDir)
            
    def _findMainPackagePath(self):
        path = os.path.realpath(__file__) 
        while os.path.dirname(path) != path:
            if os.path.exists(os.path.join(path, 'lunchinator', '__init__.py')):
                return path
            path = os.path.dirname(path)
        if hasattr(sys, "_MEIPASS"):  #pyinstaller, only for Windows
            return sys._MEIPASS
        return None
    
    def _findResourcesPath(self, defaultPath):    
        possibilities = [defaultPath, "/usr/share/lunchinator", "/usr/local/share/lunchinator"]
        if hasattr(sys, "_MEIPASS"): #pyinstaller            
            possibilities = [os.path.dirname(sys.executable)] + possibilities
        for poss in possibilities:
            if os.path.exists(os.path.join(poss, "images", "lunchinator.png")):
                return poss
        return None    
    
    def get_plugins_enabled(self):
        return self._load_plugins
    
    def set_plugins_enabled(self, enable):
        self._load_plugins = enable
            
    def set_option(self, o, v, **kwargs):
        """Set an option by its name.
        
        o -- option name
        v -- new value
        init -- True when the option is set to its initial value.
        """
        methodname = "set_" + o
        if hasattr(self, methodname): 
            _member = getattr(self, methodname)
            _member(v, **kwargs)
        else:
            getCoreLogger().warning("settings has no setter for '%s'", o)
        
        return self.get_option(o)
    
    def get_option(self, o):
        """Get an option by its name."""
        methodname = "get_" + o
        if hasattr(self, methodname): 
            _member = getattr(self, methodname)
            return _member()
        else:
            getCoreLogger().warning("settings has no attribute called '%s'", o)
        return None
            
    def read_config_from_hd(self): 
        self._config_file.read(self._main_config_dir + '/settings.cfg')
        
        # load gui settings
        for tup, _val in self.get_gui_settings():
            option = tup[0]
            value = self.read_value_from_config_file(self.get_option(option), "general", option)
            self.set_option(option, value, init=True)
            
        # load hidden settings
        for option in self.get_hidden_settings():
            value = self.read_value_from_config_file(self.get_option(option), "general", option)
            self.set_option(option, value, init=True)
        
        # load settings that don't fit the default schema        
        self._ID = self.read_value_from_config_file(self._ID, "general", "ID")      
        self._available_db_connections = self.read_value_from_config_file(self._available_db_connections, "general", "available_db_connections")
        self._multiple_machines_allowed = self.read_value_from_config_file(self._multiple_machines_allowed , "general", "multiple_machines_allowed")
        externalRepos = self.read_value_from_config_file(None, "general", "external_plugin_repos")
        
        componentLoggingLevels = self.read_value_from_config_file(None, "general", "comp_logging_levels")
        if componentLoggingLevels:
            deserializeLoggingLevels(componentLoggingLevels)
            
        if externalRepos == None:
            if os.path.isdir(self.get_config("plugins")):
                externalRepos = [(self.get_config("plugins"), True, False)]  # active, but no auto update
            else:
                externalRepos = []
        else:
            externalRepos = json.loads(externalRepos)
            
        self._plugin_repos = PluginRepositories(self.get_resource("plugins"), externalRepos, logging=self.get_verbose())
        
        if len(self._ID)==0:
            self.generate_ID(init=True)
            
    def read_value_from_config_file(self, value, section, name):
        try:
            if type(value) is types.BooleanType:
                value = self._config_file.getboolean(section, name)
            elif type(value) is types.IntType:
                value = self._config_file.getint(section, name)
            elif type(value) is types.ListType:                
                value = [unicode(x) for x in self._config_file.get(section, name).split(";;")]
            else:
                value = unicode(self._config_file.get(section, name))
        except ConfigParser.NoSectionError:
            self._config_file.add_section(section)
        except ConfigParser.NoOptionError:
            pass
        except ValueError:
            getCoreLogger().error("Value of setting, %s has wrong type.", name)
        except:
            getCoreLogger().exception("error while reading %s from config file", name)
        return value
        
    def write_config_to_hd(self):
        self.get_config_file().set('general', 'external_plugin_repos', json.dumps(self.get_plugin_repositories().getExternalRepositories()))
        levels = serializeLoggingLevels()
        if levels:
            self.get_config_file().set('general', 'comp_logging_levels', levels)
        else:
            self.get_config_file().remove_option('general', 'comp_logging_levels')
        with codecs.open(self._main_config_dir + '/settings.cfg', 'w', 'utf-8') as f: 
            self._config_file.write(f)
    
    def get_main_package_path(self):
        return self._main_package_path
    
    def get_resources_path(self):
        return self._resources_path
    
    def get_resource(self, *args):
        res = unicode(os.path.join(self.get_resources_path(), *args))
        if not os.path.exists(res):
            raise IOError("Resource %s does not exist." % res)
        return res
    
    def get_main_config_dir(self):
        return self._main_config_dir
    
    def get_config(self, *args):
        return unicode(os.path.join(self.get_main_config_dir(), *args))
    
    def get_plugin_dirs(self):
        # getPluginDirs is thread safe
        return self._plugin_repos.getPluginDirs()
    
    def get_plugin_repositories(self):
        return self._plugin_repos

    def get_config_file(self):
        return self._config_file
    
    def get_peers_file(self):
        return self._peers_file
    
    def get_members_file(self):
        """Deprecated: Use get_peers_file"""
        return self._members_file
    
    def get_messages_file(self):
        return self._messages_file

    def get_legacy_messages_file(self):
        return self._legacy_messages_file
    
    def get_version(self):
        if self._version == None:
            try:
                version_file = self.get_resource("version")
                with contextlib.closing(open(version_file, "r")) as vfh:
                    self._version = vfh.read().strip()
                self._commit_count = self._version.split(".")[-1]
            except Exception:
                from lunchinator.git import GitHandler
                gh = GitHandler(getCoreLogger())
                if gh.hasGit():
                    commit_count = gh.getCommitCount()
                    if commit_count:
                        self._commit_count = commit_count
                        self._version = commit_count
                else:
                    getCoreLogger().error("Error reading/parsing version file")
                    self._version = u"unknown.unknown"
                    self._commit_count = "unknown"
                
        return self._version
    
    def get_commit_count(self):
        self.get_version()
        
        return self._commit_count
    
    def log_file(self):
        return self._log_file
    
    def get_ID(self):
        return self._ID
    @hidden_setting(sendInfoDict=True)
    def set_ID(self, v):
        """to generate a new ID use generate_ID instead
        """
        self._ID = v
    
    def generate_ID(self, init=False):        
        self.set_ID(unicode(uuid.uuid4()), init=init)
    
    # the rest is read from/written to the config file
    def get_user_name(self):
        return self._user_name    
    @gui_setting(u"User Name", sendInfoDict=True)
    def set_user_name(self, name):
        self._user_name = convert_string(name)
       
    def get_lunch_trigger(self):
        return self._lunch_trigger
    @gui_setting(u"Word that triggers alarm")
    def set_lunch_trigger(self, value):
        self._lunch_trigger = value
             
    def get_group(self):
        return self._group
    @gui_setting(u"Group Name")
    def set_group(self, value, init=False):
        from lunchinator import get_server
        oldGroup = self._group
        self._group = value
        if not init:
            getCoreLogger().info("Changing Group: '%s' -> '%s'", oldGroup, self._group)
            get_server().changeGroup(unicode(value))
            get_notification_center().emitGroupChanged(oldGroup, self._group)
      
    def get_avatar_dir(self):
        return self._avatar_dir
                 
    def get_avatar_file(self):
        return self.get_avatar()
    @hidden_setting()
    def set_avatar_file(self, file_name):  
        if file_name and not os.path.exists(os.path.join(self._avatar_dir, file_name)):
            getCoreLogger().error("avatar does not exist: %s", file_name)
            return
        self._avatar_file = convert_string(file_name)
        
    def get_avatar(self):
        return self._avatar_file
    
    def _check_lunch_time(self, new_value, old_value):
        if new_value == old_value:
            return new_value
        try:
            time = datetime.strptime(new_value, lunch_settings.LUNCH_TIME_FORMAT)
            if time:
                return new_value
        except:
            getCoreLogger().warning("Problem while checking the lunch time")
        getCoreLogger().warning("Illegal time format: %s", new_value)
        return old_value
    
    def get_default_lunch_begin(self):
        return self._default_lunch_begin
    @gui_setting(u"Free for lunch from", sendInfoDict=True)
    def set_default_lunch_begin(self, new_value):
        new_value = convert_string(new_value)
        self._default_lunch_begin = self._check_lunch_time(new_value, self._default_lunch_begin)
    
    def get_default_lunch_end(self):
        return self._default_lunch_end
    @gui_setting(u"Free for lunch until", sendInfoDict=True)
    def set_default_lunch_end(self, new_value):
        new_value = convert_string(new_value)
        self._default_lunch_end = self._check_lunch_time(new_value, self._default_lunch_end)
        
    def get_next_lunch_begin(self):
        # reset "next" lunch times after they are over
        if self._next_lunch_begin:
            return self._next_lunch_begin
        return self.get_default_lunch_begin()
        
    def get_next_lunch_end(self):
        # reset "next" lunch times after they are over
        if self._next_lunch_end:
            if self.get_next_lunch_reset_time() > 0:
                return self._next_lunch_end
            else:
                # reset
                self._next_lunch_begin = None
                self._next_lunch_end = None
        return self.get_default_lunch_end()
    
    def set_next_lunch_time(self, begin_time, end_time):
        if begin_time == None:
            self._next_lunch_begin, self._next_lunch_end = None, None
            
        begin_time = convert_string(begin_time)
        self._next_lunch_begin = self._check_lunch_time(begin_time, self._next_lunch_begin)
        end_time = convert_string(end_time)
        self._next_lunch_end = self._check_lunch_time(end_time, self._next_lunch_end)
    
    def get_next_lunch_reset_time(self):
        if self._next_lunch_end == None:
            return None
        
        from lunchinator.utilities import getTimeDelta
        # reset after next_lunch_end, but not before default_lunch_end
        
        tdn = getTimeDelta(self._next_lunch_end, getCoreLogger())
        tdd = getTimeDelta(self.get_default_lunch_end(), getCoreLogger())
        
        return max(tdn, tdd)
    
    def get_warn_if_members_not_ready(self):
        return self._warn_if_members_not_ready
    @gui_setting(u"Warn if members are not ready for lunch")
    def set_warn_if_members_not_ready(self, new_value):
        self._warn_if_members_not_ready = new_value
        
    def get_notification_if_everybody_ready(self):
        return self._notification_if_everybody_ready
    @gui_setting(u"Notification if everybody is ready for lunch")
    def set_notification_if_everybody_ready(self, new_value):
        self._notification_if_everybody_ready = new_value
    
    def get_alarm_begin_time(self):
        return self._alarm_begin_time
    @gui_setting(u"No alarm before")
    def set_alarm_begin_time(self, new_value):
        new_value = convert_string(new_value)
        self._alarm_begin_time = self._check_lunch_time(new_value, self._alarm_begin_time)
    
    def get_alarm_end_time(self):
        return self._alarm_end_time
    @gui_setting(u"No alarm after")
    def set_alarm_end_time(self, new_value):
        new_value = convert_string(new_value)
        self._alarm_end_time = self._check_lunch_time(new_value, self._alarm_end_time)
    
    def get_mute_timeout(self):
        return self._mute_timeout
    @gui_setting(u"Mute for x sec after alarm")
    def set_mute_timeout(self, new_value):
        self._mute_timeout = new_value
    
    def get_peer_timeout(self):
        return self._peer_timeout
    @hidden_setting()
    def set_peer_timeout(self, v):
        self._peer_timeout = v
        
    def get_max_fragment_length(self):
        return self._max_fragment_length
    @hidden_setting()
    def set_max_fragment_length(self, v):
        self._max_fragment_length = v
        
    def get_udp_port(self):
        return self._udp_port
    @hidden_setting()
    def set_udp_port(self, v):
        self._udp_port = v
        
    def get_message_cache_timeout(self):
        return self._message_cache_timeout
    @hidden_setting()
    def set_message_cache_timeout(self, v):
        self._message_cache_timeout = v
        
    def get_tcp_port(self):
        return self._tcp_port
    @gui_setting(u"TCP port", restart=True)
    def set_tcp_port(self, new_value):
        self._tcp_port = new_value
    
    def get_logging_level(self):
        return self._logging_level
    @hidden_setting()
    def set_logging_level(self, newValue):
        self._logging_level = convert_string(newValue)
        if self._logging_level.upper() == u"CRITICAL":
            setGlobalLoggingLevel(logging.CRITICAL)
        elif self._logging_level.upper() == u"ERROR":
            setGlobalLoggingLevel(logging.ERROR)
        elif self._logging_level.upper() == u"WARNING":
            setGlobalLoggingLevel(logging.WARNING)
        elif self._logging_level.upper() == u"INFO":
            setGlobalLoggingLevel(logging.INFO)
        elif self._logging_level.upper() == u"DEBUG":
            setGlobalLoggingLevel(logging.DEBUG)
        
    def get_log_cache_size(self):
        return self._log_cache_size
    @hidden_setting()
    def set_log_cache_size(self, newValue):
        from lunchinator.log.lunch_logger import setLogCacheSize
        self._log_cache_size = newValue
        setLogCacheSize(newValue)
        
    def set_verbose(self, verbose):
        """Set True to override logging level"""
        self._verbose = verbose
    def get_verbose(self):
        return self._verbose or getLoggingLevel(None) == logging.DEBUG
        
    def get_group_plugins(self):
        return self._group_plugins
    @gui_setting(u"Group plugins by category", restart=True)
    def set_group_plugins(self, newValue):
        self._group_plugins = newValue            
        
    def get_default_db_connection(self):
        return self._default_db_connection
    
    def set_default_db_connection(self, newValue):
        self._default_db_connection = newValue
        
    # always force at least one connection
    def get_available_db_connections(self):
        conn = self._available_db_connections
        if len(conn):
            return conn
        else:
            return [u'Standard']
    
    def set_available_db_connections(self, newValue):
        self._available_db_connections = newValue
        self._config_file.set('general', 'available_db_connections', str(";;".join(newValue)))
            
    def get_proxy(self):
        return self._proxy
    @gui_setting(u"Proxy server (usually detected automatically)", restart=True)
    def set_proxy(self, newValue, init=False):
        if newValue:
            os.environ["http_proxy"] = newValue
            os.environ["https_proxy"] = newValue
        elif not init:
            if "http_proxy" in os.environ:
                del os.environ["http_proxy"]
            if "https_proxy" in os.environ:
                del os.environ["https_proxy"]
        self._proxy = newValue
        
    
    def get_multiple_machines_allowed(self):
        return self._multiple_machines_allowed
    def add_multiple_machines_allowed(self, newValue):
        self._multiple_machines_allowed += [newValue]
        v = ";;".join(self._multiple_machines_allowed)
        self._config_file.set('general', 'multiple_machines_allowed', str(v))