make sure unexported modules are initialized
take the opportunity for a small redesign: - create a new method build_descriptive_data which calls secnode.get_modules also on unexported modules. + cache descriptive data Change-Id: I4a0b8ac96108463dc0c800bb11a404206c26b092 Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36089 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
parent
1fead8b2c6
commit
9545cb4188
@ -265,9 +265,9 @@ class Dispatcher:
|
||||
modulename, exportedname = specifier, None
|
||||
if ':' in specifier:
|
||||
modulename, exportedname = specifier.split(':', 1)
|
||||
if modulename not in self.secnode.export:
|
||||
raise NoSuchModuleError(f'Module {modulename!r} does not exist')
|
||||
moduleobj = self.secnode.get_module(modulename)
|
||||
if moduleobj is None or not moduleobj.export:
|
||||
raise NoSuchModuleError(f'Module {modulename!r} does not exist')
|
||||
if exportedname is not None:
|
||||
pname = moduleobj.accessiblename2attr.get(exportedname, True)
|
||||
if pname and pname not in moduleobj.accessibles:
|
||||
@ -281,7 +281,7 @@ class Dispatcher:
|
||||
else:
|
||||
# activate all modules
|
||||
self._active_connections.add(conn)
|
||||
modules = [(m, None) for m in self.secnode.export]
|
||||
modules = [(m, None) for m in self.secnode.get_exported_modules()]
|
||||
|
||||
# send updates for all subscribed values.
|
||||
# note: The initial poll already happend before the server is active
|
||||
|
@ -44,8 +44,6 @@ class SecNode:
|
||||
self.nodeprops = {}
|
||||
# map ALL modulename -> moduleobj
|
||||
self.modules = {}
|
||||
# list of EXPORTED modules
|
||||
self.export = []
|
||||
self.log = logger
|
||||
self.srv = srv
|
||||
# set of modules that failed creation
|
||||
@ -193,60 +191,62 @@ class SecNode:
|
||||
modname, len(pinata_modules))
|
||||
todos.extend(pinata_modules)
|
||||
|
||||
def export_accessibles(self, modulename):
|
||||
self.log.debug('export_accessibles(%r)', modulename)
|
||||
if modulename in self.export:
|
||||
# omit export=False params!
|
||||
res = OrderedDict()
|
||||
for aobj in self.get_module(modulename).accessibles.values():
|
||||
if aobj.export:
|
||||
res[aobj.export] = aobj.for_export()
|
||||
self.log.debug('list accessibles for module %s -> %r',
|
||||
modulename, res)
|
||||
return res
|
||||
self.log.debug('-> module is not to be exported!')
|
||||
return OrderedDict()
|
||||
def export_accessibles(self, modobj):
|
||||
self.log.debug('export_accessibles(%r)', modobj.name)
|
||||
# omit export=False params!
|
||||
res = OrderedDict()
|
||||
for aobj in modobj.accessibles.values():
|
||||
if aobj.export:
|
||||
res[aobj.export] = aobj.for_export()
|
||||
self.log.debug('list accessibles for module %s -> %r',
|
||||
modobj.name, res)
|
||||
return res
|
||||
|
||||
def build_descriptive_data(self):
|
||||
modules = {}
|
||||
result = {'modules': modules}
|
||||
for modulename in self.modules:
|
||||
modobj = self.get_module(modulename)
|
||||
if not modobj.export:
|
||||
continue
|
||||
# some of these need rework !
|
||||
mod_desc = {'accessibles': self.export_accessibles(modobj)}
|
||||
mod_desc.update(modobj.exportProperties())
|
||||
mod_desc.pop('export', None)
|
||||
modules[modulename] = mod_desc
|
||||
result['equipment_id'] = self.equipment_id
|
||||
result['firmware'] = 'FRAPPY ' + get_version()
|
||||
result['description'] = self.nodeprops['description']
|
||||
for prop, propvalue in self.nodeprops.items():
|
||||
if prop.startswith('_'):
|
||||
result[prop] = propvalue
|
||||
self.descriptive_data = result
|
||||
|
||||
def get_descriptive_data(self, specifier):
|
||||
"""returns a python object which upon serialisation results in the
|
||||
descriptive data"""
|
||||
specifier = specifier or ''
|
||||
modules = {}
|
||||
result = {'modules': modules}
|
||||
for modulename in self.export:
|
||||
module = self.get_module(modulename)
|
||||
if not module.export:
|
||||
continue
|
||||
# some of these need rework !
|
||||
mod_desc = {'accessibles': self.export_accessibles(modulename)}
|
||||
mod_desc.update(module.exportProperties())
|
||||
mod_desc.pop('export', False)
|
||||
modules[modulename] = mod_desc
|
||||
modname, _, pname = specifier.partition(':')
|
||||
modules = self.descriptive_data['modules']
|
||||
if modname in modules: # extension to SECoP standard: description of a single module
|
||||
result = modules[modname]
|
||||
if pname in result['accessibles']: # extension to SECoP standard: description of a single accessible
|
||||
# command is also accepted
|
||||
result = result['accessibles'][pname]
|
||||
elif pname:
|
||||
return result['accessibles'][pname]
|
||||
if pname:
|
||||
raise NoSuchParameterError(f'Module {modname!r} '
|
||||
f'has no parameter {pname!r}')
|
||||
elif not modname or modname == '.':
|
||||
result['equipment_id'] = self.equipment_id
|
||||
result['firmware'] = 'FRAPPY ' + get_version()
|
||||
result['description'] = self.nodeprops['description']
|
||||
for prop, propvalue in self.nodeprops.items():
|
||||
if prop.startswith('_'):
|
||||
result[prop] = propvalue
|
||||
else:
|
||||
raise NoSuchModuleError(f'Module {modname!r} does not exist')
|
||||
return result
|
||||
return result
|
||||
if not modname or modname == '.':
|
||||
return self.descriptive_data
|
||||
raise NoSuchModuleError(f'Module {modname!r} does not exist')
|
||||
|
||||
def get_exported_modules(self):
|
||||
return [m for m, o in self.modules.items() if o.export]
|
||||
|
||||
def add_module(self, module, modulename):
|
||||
"""Adds a named module object to this SecNode."""
|
||||
self.modules[modulename] = module
|
||||
if module.export:
|
||||
self.export.append(modulename)
|
||||
|
||||
# def remove_module(self, modulename_or_obj):
|
||||
# moduleobj = self.get_module(modulename_or_obj)
|
||||
|
@ -289,7 +289,6 @@ class Server:
|
||||
If there are errors that occur, they will be collected and emitted
|
||||
together in the end.
|
||||
"""
|
||||
errors = []
|
||||
opts = dict(self.node_cfg)
|
||||
cls = get_class(opts.pop('cls'))
|
||||
self.secnode = SecNode(self.name, self.log.getChild('secnode'), opts, self)
|
||||
@ -301,10 +300,9 @@ class Server:
|
||||
self.secnode.add_secnode_property(k, opts.pop(k))
|
||||
|
||||
self.secnode.create_modules()
|
||||
# initialize all modules by getting them with Dispatcher.get_module,
|
||||
# which is done in the get_descriptive data
|
||||
# TODO: caching, to not make this extra work
|
||||
self.secnode.get_descriptive_data('')
|
||||
# initialize modules by calling self.secnode.get_module for all of them
|
||||
# this is done in build_descriptive_data even for unexported modules
|
||||
self.secnode.build_descriptive_data()
|
||||
# =========== All modules are initialized ===========
|
||||
|
||||
# all errors from initialization process
|
||||
|
Loading…
x
Reference in New Issue
Block a user