def __init__(self, args: argparse.Namespace) -> None: """Initialize the Rotkehlchen object May Raise: - SystemPermissionError if the given data directory's permissions are not correct. """ self.lock = Semaphore() self.lock.acquire() # Can also be None after unlock if premium credentials did not # authenticate or premium server temporarily offline self.premium: Optional[Premium] = None self.user_is_logged_in: bool = False configure_logging(args) self.sleep_secs = args.sleep_secs if args.data_dir is None: self.data_dir = default_data_directory() else: self.data_dir = Path(args.data_dir) if not os.access(self.data_dir, os.W_OK | os.R_OK): raise SystemPermissionError( f'The given data directory {self.data_dir} is not readable or writable', ) self.args = args self.msg_aggregator = MessagesAggregator() self.greenlet_manager = GreenletManager(msg_aggregator=self.msg_aggregator) self.exchange_manager = ExchangeManager(msg_aggregator=self.msg_aggregator) # Initialize the AssetResolver singleton AssetResolver(data_directory=self.data_dir) self.data = DataHandler(self.data_dir, self.msg_aggregator) self.cryptocompare = Cryptocompare(data_directory=self.data_dir, database=None) self.coingecko = Coingecko() self.icon_manager = IconManager(data_dir=self.data_dir, coingecko=self.coingecko) self.greenlet_manager.spawn_and_track( after_seconds=None, task_name='periodically_query_icons_until_all_cached', method=self.icon_manager.periodically_query_icons_until_all_cached, batch_size=ICONS_BATCH_SIZE, sleep_time_secs=ICONS_QUERY_SLEEP, ) # Initialize the Inquirer singleton Inquirer( data_dir=self.data_dir, cryptocompare=self.cryptocompare, coingecko=self.coingecko, ) # Keeps how many trades we have found per location. Used for free user limiting self.actions_per_location: Dict[str, Dict[Location, int]] = { 'trade': defaultdict(int), 'asset_movement': defaultdict(int), } self.lock.release() self.shutdown_event = gevent.event.Event()
def __init__(self, args: argparse.Namespace) -> None: """Initialize the Rotkehlchen object This runs during backend initialization so it should be as light as possible. May Raise: - SystemPermissionError if the given data directory's permissions are not correct. """ # Can also be None after unlock if premium credentials did not # authenticate or premium server temporarily offline self.premium: Optional[Premium] = None self.user_is_logged_in: bool = False configure_logging(args) self.sleep_secs = args.sleep_secs if args.data_dir is None: self.data_dir = default_data_directory() else: self.data_dir = Path(args.data_dir) self.data_dir.mkdir(parents=True, exist_ok=True) if not os.access(self.data_dir, os.W_OK | os.R_OK): raise SystemPermissionError( f'The given data directory {self.data_dir} is not readable or writable', ) self.main_loop_spawned = False self.args = args self.api_task_greenlets: List[gevent.Greenlet] = [] self.msg_aggregator = MessagesAggregator() self.greenlet_manager = GreenletManager( msg_aggregator=self.msg_aggregator) self.exchange_manager = ExchangeManager( msg_aggregator=self.msg_aggregator) # Initialize the GlobalDBHandler singleton. Has to be initialized BEFORE asset resolver GlobalDBHandler(data_dir=self.data_dir) self.data = DataHandler(self.data_dir, self.msg_aggregator) self.cryptocompare = Cryptocompare(data_directory=self.data_dir, database=None) self.coingecko = Coingecko() self.icon_manager = IconManager(data_dir=self.data_dir, coingecko=self.coingecko) self.assets_updater = AssetsUpdater(self.msg_aggregator) # Initialize the Inquirer singleton Inquirer( data_dir=self.data_dir, cryptocompare=self.cryptocompare, coingecko=self.coingecko, ) # Keeps how many trades we have found per location. Used for free user limiting self.actions_per_location: Dict[str, Dict[Location, int]] = { 'trade': defaultdict(int), 'asset_movement': defaultdict(int), } self.task_manager: Optional[TaskManager] = None self.shutdown_event = gevent.event.Event()
def file_md5(filepath: Path) -> str: """Gets the hexadecimal string representation of the md5 hash of filepath Before calling the function, caller has to make sure path exists and is a file May raise: - SystemPermissionError if the file can't be accessed for some reason """ md5_hash = hashlib.md5() try: with open(filepath, 'rb') as f: # Read and update hash in chunks of 4K for byte_block in iter(lambda: f.read(4096), b''): md5_hash.update(byte_block) except PermissionError as e: raise SystemPermissionError(f'Failed to open: {filepath}. {str(e)}') return md5_hash.hexdigest()
def __init__(self, args: argparse.Namespace) -> None: """Initialize the Rotkehlchen object May Raise: - SystemPermissionError if the given data directory's permissions are not correct. """ self.lock = Semaphore() self.lock.acquire() # Can also be None after unlock if premium credentials did not # authenticate or premium server temporarily offline self.premium: Optional[Premium] = None self.user_is_logged_in: bool = False configure_logging(args) self.sleep_secs = args.sleep_secs if args.data_dir is None: self.data_dir = default_data_directory() else: self.data_dir = Path(args.data_dir) if not os.access(self.data_dir, os.W_OK | os.R_OK): raise SystemPermissionError( f'The given data directory {self.data_dir} is not readable or writable', ) self.args = args self.msg_aggregator = MessagesAggregator() self.greenlet_manager = GreenletManager( msg_aggregator=self.msg_aggregator) self.exchange_manager = ExchangeManager( msg_aggregator=self.msg_aggregator) self.data = DataHandler(self.data_dir, self.msg_aggregator) self.cryptocompare = Cryptocompare(data_directory=self.data_dir, database=None) # Initialize the Inquirer singleton Inquirer(data_dir=self.data_dir, cryptocompare=self.cryptocompare) self.lock.release() self.shutdown_event = gevent.event.Event()
def unlock( self, username: str, password: str, create_new: bool, initial_settings: Optional[ModifiableDBSettings] = None, ) -> Path: """Unlocks a user, either logging them in or creating a new user May raise: - SystemPermissionError if there are permission errors when accessing the DB or a directory in the user's filesystem - AuthenticationError if the given user does not exist, or if sqlcipher version problems are detected - DBUpgradeError if the rotki DB version is newer than the software or there is a DB upgrade and there is an error. """ user_data_dir = self.data_directory / username if create_new: try: if (user_data_dir / 'rotkehlchen.db').exists(): raise AuthenticationError( f'User {username} already exists. User data dir: {user_data_dir}', ) else: user_data_dir.mkdir(exist_ok=True) except PermissionError as e: raise SystemPermissionError(f'Failed to create directory for user: {str(e)}') else: try: if not user_data_dir.exists(): raise AuthenticationError('User {} does not exist'.format(username)) if not (user_data_dir / 'rotkehlchen.db').exists(): raise PermissionError except PermissionError: # This is bad. User directory exists but database is missing. # Or either DB or user directory can't be accessed due to permissions # Make a backup of the directory that user should probably remove # on their own. At the same time delete the directory so that a new # user account can be created shutil.move( user_data_dir, # type: ignore self.data_directory / f'auto_backup_{username}_{ts_now()}', ) raise SystemPermissionError( 'User {} exists but DB is missing. Somehow must have been manually ' 'deleted or is corrupt or access permissions do not allow reading. ' 'Please recreate the user account. ' 'A backup of the user directory was created.'.format(username)) self.db: DBHandler = DBHandler( user_data_dir=user_data_dir, password=password, msg_aggregator=self.msg_aggregator, initial_settings=initial_settings, ) self.user_data_dir = user_data_dir self.logged_in = True self.username = username self.password = password return user_data_dir
def __init__(self, args: argparse.Namespace) -> None: """Initialize the Rotkehlchen object May Raise: - SystemPermissionError if the given data directory's permissions are not correct. """ self.lock = Semaphore() self.lock.acquire() # Can also be None after unlock if premium credentials did not # authenticate or premium server temporarily offline self.premium: Optional[Premium] = None self.user_is_logged_in = False logfilename = None if args.logtarget == 'file': logfilename = args.logfile if args.loglevel == 'debug': loglevel = logging.DEBUG elif args.loglevel == 'info': loglevel = logging.INFO elif args.loglevel == 'warn': loglevel = logging.WARN elif args.loglevel == 'error': loglevel = logging.ERROR elif args.loglevel == 'critical': loglevel = logging.CRITICAL else: raise AssertionError('Should never get here. Illegal log value') logging.basicConfig( filename=logfilename, filemode='w', level=loglevel, format='%(asctime)s -- %(levelname)s:%(name)s:%(message)s', datefmt='%d/%m/%Y %H:%M:%S %Z', ) if not args.logfromothermodules: logging.getLogger('urllib3').setLevel(logging.CRITICAL) logging.getLogger('urllib3.connectionpool').setLevel( logging.CRITICAL) self.sleep_secs = args.sleep_secs self.data_dir = args.data_dir if not os.access(self.data_dir, os.W_OK | os.R_OK): raise SystemPermissionError( f'The given data directory {self.data_dir} is not readable or writable', ) self.args = args self.msg_aggregator = MessagesAggregator() self.greenlet_manager = GreenletManager( msg_aggregator=self.msg_aggregator) self.exchange_manager = ExchangeManager( msg_aggregator=self.msg_aggregator) self.all_eth_tokens = AssetResolver().get_all_eth_tokens() self.data = DataHandler(self.data_dir, self.msg_aggregator) self.cryptocompare = Cryptocompare(data_directory=self.data_dir, database=None) # Initialize the Inquirer singleton Inquirer(data_dir=self.data_dir, cryptocompare=self.cryptocompare) self.lock.release() self.shutdown_event = gevent.event.Event()
def unlock( self, username: str, password: str, create_new: bool, ) -> FilePath: """Unlocks a user, either logging them in or creating a new user May raise: - SystemPermissionError if there are permission errors when accessing the DB or a directory in the user's filesystem - AuthenticationError if the given user does not exist, or if sqlcipher version problems are detected - DBUpgradeError if the rotki DB version is newer than the software or there is a DB upgrade and there is an error. """ user_data_dir = FilePath(os.path.join(self.data_directory, username)) if create_new: if os.path.exists(user_data_dir): raise AuthenticationError( 'User {} already exists'.format(username)) else: try: os.mkdir(user_data_dir) except PermissionError as e: raise SystemPermissionError( f'Failed to create directory for user: {str(e)}') else: if not os.path.exists(user_data_dir): raise AuthenticationError( 'User {} does not exist'.format(username)) if not os.path.exists(os.path.join(user_data_dir, 'rotkehlchen.db')): # This is bad. User directory exists but database is missing. # Make a backup of the directory that user should probably remove # on their own. At the same time delete the directory so that a new # user account can be created shutil.move( user_data_dir, os.path.join( self.data_directory, f'auto_backup_{username}_{ts_now()}', ), ) raise SystemPermissionError( 'User {} exists but DB is missing. Somehow must have been manually ' 'deleted or is corrupt or access permissions do not allow reading. ' 'Please recreate the user account. ' 'A backup of the user directory was created.'.format( username)) self.db: DBHandler = DBHandler(user_data_dir, password, self.msg_aggregator) self.user_data_dir = user_data_dir self.logged_in = True self.username = username self.password = password return user_data_dir