simplify session's code

This commit is contained in:
Emmanuel Garette 2019-12-03 21:20:28 +01:00
parent bb1fdcbad0
commit b944a609a5
3 changed files with 133 additions and 165 deletions

View File

@ -13,19 +13,18 @@ from ...register import register
from ...config import ROOT_CACHE_DIR, DATABASE_DIR, DEBUG, ROUGAIL_DTD_PATH from ...config import ROOT_CACHE_DIR, DATABASE_DIR, DEBUG, ROUGAIL_DTD_PATH
from ...context import Context from ...context import Context
from ...utils import _ from ...utils import _
from ...error import CallError, NotAllowedError, RegistrationError from ...error import CallError, RegistrationError
from ...logger import log from ...logger import log
if not isdir(ROOT_CACHE_DIR):
raise RegistrationError(_(f'unable to find the cache dir "{ROOT_CACHE_DIR}"'))
class Risotto(Controller): class Risotto(Controller):
servermodel = {} servermodel = {}
server = {} server = {}
def __init__(self) -> None: def __init__(self) -> None:
for dirname in [ROOT_CACHE_DIR, DATABASE_DIR, ROUGAIL_DTD_PATH]:
if not isdir(dirname):
raise RegistrationError(_(f'unable to find the cache dir "{dirname}"'))
self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR) self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR)
super().__init__() super().__init__()

View File

@ -21,19 +21,47 @@ class Risotto(Controller):
def __init__(self): def __init__(self):
self.modify_storage = Storage(engine='dictionary') self.modify_storage = Storage(engine='dictionary')
def valid_user(self, def get_storage(self,
session_id: str, type: str):
risotto_context: Context, if type == 'server':
type: str) -> None: return storage_server
""" check if current user is the session owner return storage_servermodel
def get_session(self,
session_id: str,
type: str) -> Dict:
""" Get session information from storage
""" """
if type == 'server': if type == 'server':
storage = storage_server storage = storage_server
else: else:
storage = storage_servermodel storage = storage_servermodel
username = risotto_context.username return storage.get_session(session_id)
if username != storage.get_session(session_id)['username']:
raise NotAllowedError() def get_session_informations(self,
risotto_context: Context,
session_id: str,
type: str) -> Dict:
""" format session with a session ID name
"""
session = self.get_session(session_id,
type,
risotto_context.username)
return self.format_session(session_id,
session)
def format_session(self,
session_name: str,
session: Dict) -> Dict:
""" format session
"""
return {'session_id': session_name,
'id': session['id'],
'username': session['username'],
'timestamp': session['timestamp'],
'namespace': session['namespace'],
'mode': session['mode'],
'debug': session['debug']}
@register(['v1.session.server.start', 'v1.session.servermodel.start'], None) @register(['v1.session.server.start', 'v1.session.servermodel.start'], None)
async def start_session(self, async def start_session(self,
@ -46,44 +74,47 @@ class Risotto(Controller):
if type == 'server': if type == 'server':
if id not in config_module.server: if id not in config_module.server:
raise Exception(_(f'cannot find {type} with id {id}')) raise Exception(_(f'cannot find {type} with id {id}'))
server = config_module.server[id] config = config_module.server[id]['server']
config = server['server']
storage = storage_server
else: else:
if id not in config_module.servermodel: if id not in config_module.servermodel:
raise Exception(_(f'cannot find {type} with id {id}')) raise Exception(_(f'cannot find {type} with id {id}'))
config = config_module.servermodel[id] config = config_module.servermodel[id]
storage = storage_servermodel
# check if a session already exists, in this case returns it storage = self.get_storage(type)
session_list = self.list_sessions(type)
for sess in session_list: # check if a session already exists
if sess['id'] == id and sess['username'] == risotto_context.username: sessions = storage.get_sessions()
session_id = sess['session_id'] for session in sessions.values():
session = self.get_session(session_id, type) if sess['id'] == id:
return self.format_session(session_id, session) if sess['username'] == risotto_context.username:
# same user so returns it
return self.format_session(session['session_id'], session)
else:
raise CallError(_(f'{username} already edits this configuration'))
# create a new session # create a new session
while True: while True:
session_id = 'z' + hexlify(urandom(23)).decode() session_id = 'z' + hexlify(urandom(23)).decode()
if not storage.has_session(session_id): if not session_id in sessions:
break break
else:
print('session {} already exists'.format(session_id))
username = risotto_context.username
storage.add_session(session_id, storage.add_session(session_id,
config, config,
id, id,
username, risotto_context.username,
self.modify_storage) self.modify_storage)
# return session's information
return self.get_session_informations(session_id, return self.get_session_informations(session_id,
type) type)
@register(['v1.session.server.list', 'v1.session.servermodel.list'], None) @register(['v1.session.server.list', 'v1.session.servermodel.list'], None)
async def list_session_server(self, async def list_session_server(self,
risotto_context: Context): risotto_context: Context) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
return self.list_sessions(type) storage = self.get_storage(type,
risotto_context.username)
return [self.format_session(session_id, session) or session_id, session in storage.get_sessions().items()]
@register(['v1.session.server.filter', 'v1.session.servermodel.filter'], None) @register(['v1.session.server.filter', 'v1.session.servermodel.filter'], None)
async def filter_session(self, async def filter_session(self,
@ -93,10 +124,10 @@ class Risotto(Controller):
mode: str, mode: str,
debug: Optional[bool]): debug: Optional[bool]):
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
if type == 'server': storage = self.get_storage(type)
storage = storage_server # to validate the session right
else: storage.get_session(session_id,
storage = storage_servermodel username)
if namespace is not None: if namespace is not None:
storage.set_namespace(session_id, storage.set_namespace(session_id,
namespace) namespace)
@ -122,11 +153,9 @@ class Risotto(Controller):
value_multi: Optional[List]) -> Dict: value_multi: Optional[List]) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
session = self.get_session(session_id, session = self.get_session(session_id,
type) type,
ret = {'session_id': session_id, risotto_context.username)
'name': name} # if multi and not follower the value is in fact in value_multi
if index is not None:
ret['index'] = index
option = session['config'].option(name).option option = session['config'].option(name).option
if option.ismulti() and not option.isfollower(): if option.ismulti() and not option.isfollower():
value = value_multi value = value_multi
@ -138,12 +167,14 @@ class Risotto(Controller):
update['index'] = index update['index'] = index
updates = {'updates': [update]} updates = {'updates': [update]}
session['option'].updates(updates) session['option'].updates(updates)
ret['status'] = 'ok'
except Exception as err: except Exception as err:
if DEBUG: if DEBUG:
print_exc() print_exc()
ret['message'] = str(err) raise CallError(str(err))
ret['status'] = 'error' ret = {'session_id': session_id,
'name': name}
if index is not None:
ret['index'] = index
return ret return ret
@register(['v1.session.server.validate', 'v1.session.servermodel.validate'], None) @register(['v1.session.server.validate', 'v1.session.servermodel.validate'], None)
@ -151,37 +182,36 @@ class Risotto(Controller):
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
session = self.get_session(session_id, type) session = self.get_session(session_id,
ret = {} type,
risotto_context.username)
try: try:
session['config'].forcepermissive.option(session['namespace']).value.dict() session['config'].forcepermissive.option(session['namespace']).value.dict()
except Exception as err: except Exception as err:
ret['status'] = 'error' raise CallError(str(err))
ret['message'] = str(err) if type == 'server':
else: mandatories = list(session['config'].forcepermissive.value.mandatory())
if type == 'server': if mandatories:
mandatories = list(session['config'].forcepermissive.value.mandatory()) if len(mandatories) == 1:
if mandatories: mandatories = mandatories[0]
ret['status'] = 'incomplete' msg = _('the parameter "--{mandatories}" is mandatory')
ret['mandatories'] = mandatories
else: else:
ret['status'] = 'ok' mandatories = '", "--'.join(mandatories)
else: msg = _('parameters "{mandatories}" are mandatories')
ret['status'] = 'ok' raise CallError(msg)
return ret return self.format_session(session_id,
session)
@register(['v1.session.server.get', 'v1.session.servermodel.get'], None) @register(['v1.session.server.get', 'v1.session.servermodel.get'], None)
async def get_session_(self, async def get_session_server(self,
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
info = self.get_session_informations(session_id,
type)
info['content'] = session_id
session = self.get_session(session_id, session = self.get_session(session_id,
type) type,
risotto_context.username)
info = self.format_session(session_id, session)
info['content'] = dumps(session['option'].value.dict(fullpath=True)) info['content'] = dumps(session['option'].value.dict(fullpath=True))
return info return info
@register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None) @register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None)
@ -190,18 +220,14 @@ class Risotto(Controller):
session_id: str, session_id: str,
save: bool) -> Dict: save: bool) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
self.valid_user(session_id, storage = self.get_storage(type)
risotto_context, session = storage.get_session(session_id,
type) risotto_context.username)
session = self.get_session(session_id,
type)
id_ = session['id'] id_ = session['id']
config_module = dispatcher.get_service('config') config_module = dispatcher.get_service('config')
if type == 'server': if type == 'server':
storage = storage_server
config = config_module.server[id_]['server'] config = config_module.server[id_]['server']
else: else:
storage = storage_servermodel
config = config_module.servermodel[id_] config = config_module.servermodel[id_]
if save: if save:
modif_config = session['config'] modif_config = session['config']
@ -215,66 +241,15 @@ class Risotto(Controller):
request, request,
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
self.valid_user(session_id, session = storage_server.get_session(session_id,
risotto_context, risotto_context.username)
'server') return session['option'].dict(remotable='all')
session = storage_server.get_session(session_id)
return self.load_dict(session)
@register_http('v1', '/config/servermodel/{session_id}') @register_http('v1', '/config/servermodel/{session_id}')
async def get_servermodel_api(self, async def get_servermodel_api(self,
request, request,
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
self.valid_user(session_id, session = storage_servermodel.get_session(session_id,
risotto_context, risotto_context.username)
'servermodel')
session = storage_servermodel.get_session(session_id)
return self.load_dict(session)
def get_session(self,
session_id: str,
type: str) -> Dict:
""" Get session information from storage
"""
if type == 'server':
return storage_server.get_session(session_id)
return storage_servermodel.get_session(session_id)
def get_session_informations(self,
session_id: str,
type: str) -> Dict:
""" format session with a session ID name
"""
session = self.get_session(session_id,
type)
return self.format_session(session_id,
session)
def format_session(self,
session_name: str,
session: Dict) -> Dict:
""" format session
"""
return {'session_id': session_name,
'id': session['id'],
'username': session['username'],
'timestamp': session['timestamp'],
'namespace': session['namespace'],
'mode': session['mode'],
'debug': session['debug']}
def list_sessions(self,
type: str) -> List:
ret = []
if type == 'server':
storage = storage_server
else:
storage = storage_servermodel
for session_id, session in storage.get_sessions().items():
ret.append(self.format_session(session_id, session))
return ret
def load_dict(self,
session: Dict) -> Dict:
return session['option'].dict(remotable='all') return session['option'].dict(remotable='all')

View File

@ -1,6 +1,8 @@
import time import time
from typing import Dict
from tiramisu import Config from tiramisu import Config
from rougail import modes from rougail import modes
from ...error import CallError, NotAllowedError
class StorageError(Exception): class StorageError(Exception):
@ -13,23 +15,15 @@ class Storage(object):
def __init__(self): def __init__(self):
self.sessions = {} self.sessions = {}
def has_session(self,
id: int):
return id in self.sessions
def add_session(self, def add_session(self,
session_id: int, session_id: int,
orig_config: Config, orig_config: Config,
server_id: int, server_id: int,
username: str, username: str,
config_storage): config_storage):
for session in self.sessions.values():
if session['id'] == server_id:
raise Storage(_(f'{username} already edits this configuration'))
prefix_id = f'{session_id}_' prefix_id = f'{session_id}_'
config_name = self.get_config_name(server_id) config_name = self.get_config_name(server_id)
config_id = f'{prefix_id}{config_name}' config_id = f'{prefix_id}{config_name}'
print(config_id)
# copy Config and all it's parents # copy Config and all it's parents
meta = orig_config.config.deepcopy(session_id=config_id, meta = orig_config.config.deepcopy(session_id=config_id,
@ -41,11 +35,12 @@ class Storage(object):
while True: while True:
try: try:
children = list(config.config.list()) children = list(config.config.list())
except: if not children:
break # it's an empty metaconfig
if children: break
config = children[0] config = children[0]
else: except:
# it's a config, so no "list" method
break break
config.property.read_write() config.property.read_write()
# set the default owner # set the default owner
@ -66,35 +61,12 @@ class Storage(object):
self.set_namespace(session_id, self.set_namespace(session_id,
'creole') 'creole')
def set_namespace(self,
session_id: int,
namespace: str):
self.sessions[session_id]['option'] = self.sessions[session_id]['config'].option(namespace)
self.sessions[session_id]['namespace'] = namespace
def get_sessions(self):
return self.sessions;
def del_session(self,
id: int):
del self.sessions[id]
def get_session(self,
id: int):
if id not in self.sessions:
raise Exception(f'the session {id} not exists')
return self.sessions[id]
def get_username(self,
id: int):
return self.get_session(id)['username']
def set_config_mode(self, def set_config_mode(self,
id: int, id: int,
mode: str): mode: str):
""" Define which edition mode to select """ Define which edition mode to select
""" """
config = self.get_session(id)['config'] config = self.session[id]['config']
for mode_level in modes.values(): for mode_level in modes.values():
if modes[mode] < mode_level: if modes[mode] < mode_level:
config.property.add(mode_level.name) config.property.add(mode_level.name)
@ -105,13 +77,35 @@ class Storage(object):
def set_config_debug(self, id_, is_debug): def set_config_debug(self, id_, is_debug):
""" Enable/Disable debug mode """ Enable/Disable debug mode
""" """
config = self.get_session(id_)['config'] config = self.session[id_]['config']
if is_debug: if is_debug:
config.property.pop('hidden') config.property.pop('hidden')
else: else:
config.property.add('hidden') config.property.add('hidden')
self.sessions[id_]['debug'] = is_debug self.sessions[id_]['debug'] = is_debug
def set_namespace(self,
session_id: int,
namespace: str):
self.sessions[session_id]['option'] = self.sessions[session_id]['config'].option(namespace)
self.sessions[session_id]['namespace'] = namespace
def get_sessions(self):
return self.sessions;
def get_session(self,
id: int,
username: str) -> Dict:
if id not in self.sessions:
raise Exception(f'the session {id} not exists')
if username != storage.get_session(session_id)['username']:
raise NotAllowedError()
return self.sessions[id]
def del_session(self,
id: int):
del self.sessions[id]
class StorageServer(Storage): class StorageServer(Storage):
def get_config_name(self, def get_config_name(self,