mirror of
				https://github.com/MCV-Software/TWBlue.git
				synced 2025-10-31 04:12:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			172 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| """ A base class to be derived in possible new sessions for TWBlue and services."""
 | |
| import os
 | |
| import paths
 | |
| import output
 | |
| import time
 | |
| import sound
 | |
| import logging
 | |
| import config
 | |
| import config_utils
 | |
| import sqlitedict
 | |
| import application
 | |
| from . import session_exceptions as Exceptions
 | |
| 
 | |
| log = logging.getLogger("sessionmanager.session")
 | |
| 
 | |
| class baseSession(object):
 | |
|     """ toDo: Decorators does not seem to be working when using them in an inherited class."""
 | |
| 
 | |
|     # Decorators.
 | |
| 
 | |
|     def _require_login(fn):
 | |
|         """ Decorator for checking if the user is logged in.
 | |
|         Some functions may need this to avoid making unneeded calls."""
 | |
|         def f(self, *args, **kwargs):
 | |
|             if self.logged == True:
 | |
|                 fn(self, *args, **kwargs)
 | |
|             else:
 | |
|                 raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
 | |
|         return f
 | |
| 
 | |
|     def _require_configuration(fn):
 | |
|         """ Check if the user has a configured session."""
 | |
|         def f(self, *args, **kwargs):
 | |
|             if self.settings != None:
 | |
|                 fn(self, *args, **kwargs)
 | |
|             else:
 | |
|                 raise Exceptions.NotConfiguredSessionError("Not configured.")
 | |
|         return f
 | |
| 
 | |
|     def __init__(self, session_id):
 | |
|         """ session_id (str): The name of the folder inside the config directory where the session is located."""
 | |
|         super(baseSession, self).__init__()
 | |
|         self.session_id = session_id
 | |
|         self.logged = False
 | |
|         self.settings = None
 | |
|         self.db={}
 | |
|         # Config specification file.
 | |
|         self.config_spec = "conf.defaults"
 | |
|         # Session type.
 | |
|         self.type = "base"
 | |
| 
 | |
|     @property
 | |
|     def is_logged(self):
 | |
|         return self.logged
 | |
| 
 | |
|     def create_session_folder(self):
 | |
|         path = os.path.join(paths.config_path(), self.session_id)
 | |
|         if not os.path.exists(path):
 | |
|             log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),))
 | |
|             os.mkdir(path)
 | |
|             config.app["sessions"]["sessions"].append(id)
 | |
| 
 | |
|     def get_configuration(self):
 | |
|         """ Get settings for a session."""
 | |
|         file_ = "%s/session.conf" % (self.session_id,)
 | |
|         log.debug("Creating config file %s" % (file_,))
 | |
|         self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), self.config_spec))
 | |
|         self.init_sound()
 | |
|         self.load_persistent_data()
 | |
| 
 | |
|     def get_name(self):
 | |
|         pass
 | |
| 
 | |
|     def init_sound(self):
 | |
|         try: self.sound = sound.soundSystem(self.settings["sound"])
 | |
|         except: pass
 | |
| 
 | |
|     @_require_configuration
 | |
|     def login(self, verify_credentials=True):
 | |
|         pass
 | |
| 
 | |
|     @_require_configuration
 | |
|     def authorise(self):
 | |
|         pass
 | |
| 
 | |
|     def get_sized_buffer(self, buffer, size, reversed=False):
 | |
|         """ Returns a list with the amount of items specified by size."""
 | |
|         if isinstance(buffer, list) and size != -1 and len(buffer) > size:
 | |
|             log.debug("Requesting {} items from a list of {} items. Reversed mode: {}".format(size, len(buffer), reversed))
 | |
|             if reversed == True:
 | |
|                 return buffer[:size]
 | |
|             else:
 | |
|                 return buffer[len(buffer)-size:]
 | |
|         else:
 | |
|             return buffer
 | |
| 
 | |
|     def save_persistent_data(self):
 | |
|         """ Save the data to a persistent sqlite backed file. ."""
 | |
|         dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db")
 | |
|         log.debug("Saving storage information...")
 | |
|         # persist_size set to 0 means not saving data actually.
 | |
|         if self.settings["general"]["persist_size"] == 0:
 | |
|             if os.path.exists(dbname):
 | |
|                 os.remove(dbname)
 | |
|             return
 | |
|         # Let's check if we need to create a new SqliteDict object (when loading db in memory) or we just need to call to commit in self (if reading from disk).db.
 | |
|         # If we read from disk, we cannot modify the buffer size here as we could damage the app's integrity.
 | |
|         # We will modify buffer's size (managed by persist_size) upon loading the db into memory in app startup.
 | |
|         if self.settings["general"]["load_cache_in_memory"] and isinstance(self.db, dict):
 | |
|             log.debug("Opening database to dump memory contents...")
 | |
|             db=sqlitedict.SqliteDict(dbname, 'c')
 | |
|             for k in self.db.keys():
 | |
|                 sized_buff = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"])
 | |
|                 db[k] = sized_buff
 | |
|             db.commit(blocking=True)
 | |
|             db.close()
 | |
|             log.debug("Data has been saved in the database.")
 | |
|         else:
 | |
|             try:
 | |
|                 log.debug("Syncing new data to disk...")
 | |
|                 if hasattr(self.db, "commit"):
 | |
|                     self.db.commit()
 | |
|             except:
 | |
|                 output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True)
 | |
|                 log.exception("Exception while saving {}".format(dbname))
 | |
|                 os.remove(dbname)
 | |
| 
 | |
|     def load_persistent_data(self):
 | |
|         """Import data from a database file from user config."""
 | |
|         log.debug("Loading storage data...")
 | |
|         dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db")
 | |
|         # If persist_size is set to 0, we should remove the db file as we are no longer going to save anything.
 | |
|         if self.settings["general"]["persist_size"] == 0:
 | |
|             if os.path.exists(dbname):
 | |
|                 os.remove(dbname)
 | |
|             # Let's return from here, as we are not loading anything.
 | |
|             return
 | |
|         # try to load the db file.
 | |
|         try:
 | |
|             log.debug("Opening database...")
 | |
|             db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), dbname), 'c')
 | |
|             # If load_cache_in_memory is set to true, we will load the whole database into memory for faster access.
 | |
|             # This is going to be faster when retrieving specific objects, at the cost of more memory.
 | |
|             # Setting this to False will read the objects from database as they are needed, which might be slower for bigger datasets.
 | |
|             if self.settings["general"]["load_cache_in_memory"]:
 | |
|                 log.debug("Loading database contents into memory...")
 | |
|                 for k in db.keys():
 | |
|                     self.db[k] = db[k]
 | |
|                 db.commit(blocking=True)
 | |
|                 db.close()
 | |
|                 log.debug("Contents were loaded successfully.")
 | |
|             else:
 | |
|                 log.debug("Instantiating database from disk.")
 | |
|                 self.db = db
 | |
|                 # We must make sure we won't load more than the amount of buffer specified.
 | |
|                 log.debug("Checking if we will load all content...")
 | |
|                 for k in self.db.keys():
 | |
|                     sized_buffer = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"])
 | |
|                     self.db[k] = sized_buffer
 | |
|             if self.db.get("cursors") == None:
 | |
|                 cursors = dict(direct_messages=-1)
 | |
|                 self.db["cursors"] = cursors
 | |
|         except:
 | |
|             output.speak(_("An exception occurred while loading the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name), True)
 | |
|             log.exception("Exception while loading {}".format(dbname))
 | |
|             try: 
 | |
|                 os.remove(dbname)
 | |
|             except:
 | |
|                 pass
 | |
| 
 |