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
|
modulename, exportedname = specifier, None
|
||||||
if ':' in specifier:
|
if ':' in specifier:
|
||||||
modulename, exportedname = specifier.split(':', 1)
|
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)
|
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:
|
if exportedname is not None:
|
||||||
pname = moduleobj.accessiblename2attr.get(exportedname, True)
|
pname = moduleobj.accessiblename2attr.get(exportedname, True)
|
||||||
if pname and pname not in moduleobj.accessibles:
|
if pname and pname not in moduleobj.accessibles:
|
||||||
@ -281,7 +281,7 @@ class Dispatcher:
|
|||||||
else:
|
else:
|
||||||
# activate all modules
|
# activate all modules
|
||||||
self._active_connections.add(conn)
|
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.
|
# send updates for all subscribed values.
|
||||||
# note: The initial poll already happend before the server is active
|
# note: The initial poll already happend before the server is active
|
||||||
|
@ -44,8 +44,6 @@ class SecNode:
|
|||||||
self.nodeprops = {}
|
self.nodeprops = {}
|
||||||
# map ALL modulename -> moduleobj
|
# map ALL modulename -> moduleobj
|
||||||
self.modules = {}
|
self.modules = {}
|
||||||
# list of EXPORTED modules
|
|
||||||
self.export = []
|
|
||||||
self.log = logger
|
self.log = logger
|
||||||
self.srv = srv
|
self.srv = srv
|
||||||
# set of modules that failed creation
|
# set of modules that failed creation
|
||||||
@ -193,60 +191,62 @@ class SecNode:
|
|||||||
modname, len(pinata_modules))
|
modname, len(pinata_modules))
|
||||||
todos.extend(pinata_modules)
|
todos.extend(pinata_modules)
|
||||||
|
|
||||||
def export_accessibles(self, modulename):
|
def export_accessibles(self, modobj):
|
||||||
self.log.debug('export_accessibles(%r)', modulename)
|
self.log.debug('export_accessibles(%r)', modobj.name)
|
||||||
if modulename in self.export:
|
# omit export=False params!
|
||||||
# omit export=False params!
|
res = OrderedDict()
|
||||||
res = OrderedDict()
|
for aobj in modobj.accessibles.values():
|
||||||
for aobj in self.get_module(modulename).accessibles.values():
|
if aobj.export:
|
||||||
if aobj.export:
|
res[aobj.export] = aobj.for_export()
|
||||||
res[aobj.export] = aobj.for_export()
|
self.log.debug('list accessibles for module %s -> %r',
|
||||||
self.log.debug('list accessibles for module %s -> %r',
|
modobj.name, res)
|
||||||
modulename, res)
|
return res
|
||||||
return res
|
|
||||||
self.log.debug('-> module is not to be exported!')
|
def build_descriptive_data(self):
|
||||||
return OrderedDict()
|
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):
|
def get_descriptive_data(self, specifier):
|
||||||
"""returns a python object which upon serialisation results in the
|
"""returns a python object which upon serialisation results in the
|
||||||
descriptive data"""
|
descriptive data"""
|
||||||
specifier = specifier or ''
|
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(':')
|
modname, _, pname = specifier.partition(':')
|
||||||
|
modules = self.descriptive_data['modules']
|
||||||
if modname in modules: # extension to SECoP standard: description of a single module
|
if modname in modules: # extension to SECoP standard: description of a single module
|
||||||
result = modules[modname]
|
result = modules[modname]
|
||||||
if pname in result['accessibles']: # extension to SECoP standard: description of a single accessible
|
if pname in result['accessibles']: # extension to SECoP standard: description of a single accessible
|
||||||
# command is also accepted
|
# command is also accepted
|
||||||
result = result['accessibles'][pname]
|
return result['accessibles'][pname]
|
||||||
elif pname:
|
if pname:
|
||||||
raise NoSuchParameterError(f'Module {modname!r} '
|
raise NoSuchParameterError(f'Module {modname!r} '
|
||||||
f'has no parameter {pname!r}')
|
f'has no parameter {pname!r}')
|
||||||
elif not modname or modname == '.':
|
return result
|
||||||
result['equipment_id'] = self.equipment_id
|
if not modname or modname == '.':
|
||||||
result['firmware'] = 'FRAPPY ' + get_version()
|
return self.descriptive_data
|
||||||
result['description'] = self.nodeprops['description']
|
raise NoSuchModuleError(f'Module {modname!r} does not exist')
|
||||||
for prop, propvalue in self.nodeprops.items():
|
|
||||||
if prop.startswith('_'):
|
def get_exported_modules(self):
|
||||||
result[prop] = propvalue
|
return [m for m, o in self.modules.items() if o.export]
|
||||||
else:
|
|
||||||
raise NoSuchModuleError(f'Module {modname!r} does not exist')
|
|
||||||
return result
|
|
||||||
|
|
||||||
def add_module(self, module, modulename):
|
def add_module(self, module, modulename):
|
||||||
"""Adds a named module object to this SecNode."""
|
"""Adds a named module object to this SecNode."""
|
||||||
self.modules[modulename] = module
|
self.modules[modulename] = module
|
||||||
if module.export:
|
|
||||||
self.export.append(modulename)
|
|
||||||
|
|
||||||
# def remove_module(self, modulename_or_obj):
|
# def remove_module(self, modulename_or_obj):
|
||||||
# moduleobj = self.get_module(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
|
If there are errors that occur, they will be collected and emitted
|
||||||
together in the end.
|
together in the end.
|
||||||
"""
|
"""
|
||||||
errors = []
|
|
||||||
opts = dict(self.node_cfg)
|
opts = dict(self.node_cfg)
|
||||||
cls = get_class(opts.pop('cls'))
|
cls = get_class(opts.pop('cls'))
|
||||||
self.secnode = SecNode(self.name, self.log.getChild('secnode'), opts, self)
|
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.add_secnode_property(k, opts.pop(k))
|
||||||
|
|
||||||
self.secnode.create_modules()
|
self.secnode.create_modules()
|
||||||
# initialize all modules by getting them with Dispatcher.get_module,
|
# initialize modules by calling self.secnode.get_module for all of them
|
||||||
# which is done in the get_descriptive data
|
# this is done in build_descriptive_data even for unexported modules
|
||||||
# TODO: caching, to not make this extra work
|
self.secnode.build_descriptive_data()
|
||||||
self.secnode.get_descriptive_data('')
|
|
||||||
# =========== All modules are initialized ===========
|
# =========== All modules are initialized ===========
|
||||||
|
|
||||||
# all errors from initialization process
|
# all errors from initialization process
|
||||||
|
Loading…
x
Reference in New Issue
Block a user