changed plugin specification: use generic "handle_event" instead of "setup" and "cleanup"
fixed bug in reinitializing of plugins (Closes: #111) fixed glitch that delayed the results of the plugin_manager to go into effect by one request
This commit is contained in:
parent
0cf35e287c
commit
68e0cddc59
4 changed files with 76 additions and 54 deletions
|
@ -31,10 +31,9 @@ Python code interface:
|
||||||
- function "get_status":
|
- function "get_status":
|
||||||
- returns a string, that describes a state connected to this plugin (e.g. the current date and
|
- returns a string, that describes a state connected to this plugin (e.g. the current date and
|
||||||
time (for the "date" plugin))
|
time (for the "date" plugin))
|
||||||
- function "setup":
|
- function "handle_event(event, event_info)":
|
||||||
- may be overridden to specify bootup behaviour
|
- may be overridden to specify event handling (e.g. "bootup", "shutdown")
|
||||||
- function "cleanup":
|
- see src/cryptobox/plugins/base.py for details
|
||||||
- may be overridden to specify shutdown behaviour
|
|
||||||
- the class variable "plugin_capabilities" must be an array of strings (supported: "system" and
|
- the class variable "plugin_capabilities" must be an array of strings (supported: "system" and
|
||||||
"volume")
|
"volume")
|
||||||
- the class variable "plugin_visibility" may contain one or more of the following items:
|
- the class variable "plugin_visibility" may contain one or more of the following items:
|
||||||
|
|
|
@ -62,15 +62,16 @@ class volume_automount(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
return "volume_automount"
|
return "volume_automount"
|
||||||
|
|
||||||
|
|
||||||
def setup(self):
|
def handle_event(self, event, event_info=None):
|
||||||
"""Override bootup behaviour.
|
"""Override bootup behaviour.
|
||||||
|
|
||||||
Mount all volumes marked as 'automount'.
|
Mount all volumes marked as 'automount'.
|
||||||
"""
|
"""
|
||||||
cryptobox.plugins.base.CryptoBoxPlugin.setup(self)
|
cryptobox.plugins.base.CryptoBoxPlugin.handle_event(self, event, event_info)
|
||||||
for cont in self.cbox.get_container_list():
|
if event == "bootup":
|
||||||
if self.__is_auto_mount(cont) and not cont.is_mounted():
|
for cont in self.cbox.get_container_list():
|
||||||
cont.mount()
|
if self.__is_auto_mount(cont) and not cont.is_mounted():
|
||||||
|
cont.mount()
|
||||||
|
|
||||||
|
|
||||||
def is_useful(self, device):
|
def is_useful(self, device):
|
||||||
|
|
|
@ -90,14 +90,12 @@ class CryptoBoxPlugin:
|
||||||
return self.__module__
|
return self.__module__
|
||||||
|
|
||||||
|
|
||||||
def setup(self):
|
def handle_event(self, event_name, event_info=None):
|
||||||
"""Any plugin that wants to define bootup actions may override this.
|
"""Any plugin that wants to define event actions may override this.
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
currently only the following events are defined:
|
||||||
def cleanup(self):
|
- "bootup" (the cryptobox server is starting)
|
||||||
"""Any plugin that wants to define shutdown actions may override this.
|
- "shutdown" (the cryptobox server is stopping)
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,10 @@ GETTEXT_DOMAIN = 'cryptobox-server'
|
||||||
|
|
||||||
|
|
||||||
class PluginIconHandler:
|
class PluginIconHandler:
|
||||||
"""deliver the icons of available plugins via cherrypy"""
|
"""deliver the icons of available plugins via cherrypy
|
||||||
|
|
||||||
|
the state (enabled/disabled) and the require-auth setting is ignored to
|
||||||
|
avoid repetitive reloading"""
|
||||||
|
|
||||||
def __init__(self, plugins):
|
def __init__(self, plugins):
|
||||||
for plugin in plugins.get_plugins():
|
for plugin in plugins.get_plugins():
|
||||||
|
@ -76,13 +79,19 @@ class WebInterfaceSites:
|
||||||
self.cbox = cryptobox.core.main.CryptoBox(conf_file)
|
self.cbox = cryptobox.core.main.CryptoBox(conf_file)
|
||||||
self.__cached_language_data = None
|
self.__cached_language_data = None
|
||||||
self.__dataset = None
|
self.__dataset = None
|
||||||
self.icons = None
|
## load the plugin manager - we will not try to detect new plugins on
|
||||||
self.__plugin_manager = None
|
## the fly ...
|
||||||
|
self.__plugin_manager = cryptobox.plugins.manage.PluginManager(
|
||||||
|
self.cbox, self.cbox.prefs["Locations"]["PluginDir"], self)
|
||||||
self.__reset_dataset()
|
self.__reset_dataset()
|
||||||
## store the original http error handler
|
## store the original http error handler
|
||||||
self._cp_on_http_error = self.new_http_error_handler
|
self._cp_on_http_error = self.new_http_error_handler
|
||||||
## set initial language order
|
## set initial language order
|
||||||
self.lang_order = self.cbox.prefs["WebSettings"]["Languages"][:]
|
self.lang_order = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||||
|
## publish plugin icons
|
||||||
|
self.icons = PluginIconHandler(self.__plugin_manager)
|
||||||
|
self.icons.exposed = True
|
||||||
|
## announce that the server started up
|
||||||
self.setup()
|
self.setup()
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +101,7 @@ class WebInterfaceSites:
|
||||||
self.cbox.setup()
|
self.cbox.setup()
|
||||||
for plugin in self.__plugin_manager.get_plugins():
|
for plugin in self.__plugin_manager.get_plugins():
|
||||||
if plugin:
|
if plugin:
|
||||||
plugin.setup()
|
plugin.handle_event("bootup")
|
||||||
|
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
|
@ -102,7 +111,7 @@ class WebInterfaceSites:
|
||||||
for plugin in self.__plugin_manager.get_plugins():
|
for plugin in self.__plugin_manager.get_plugins():
|
||||||
if plugin:
|
if plugin:
|
||||||
self.cbox.log.info("Cleaning up plugin '%s' ..." % plugin.get_name())
|
self.cbox.log.info("Cleaning up plugin '%s' ..." % plugin.get_name())
|
||||||
plugin.cleanup()
|
plugin.handle_event("shutdown")
|
||||||
self.cbox.cleanup()
|
self.cbox.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,10 +123,7 @@ class WebInterfaceSites:
|
||||||
"""
|
"""
|
||||||
self.__load_plugins()
|
self.__load_plugins()
|
||||||
self.__dataset = cryptobox.web.dataset.WebInterfaceDataset(
|
self.__dataset = cryptobox.web.dataset.WebInterfaceDataset(
|
||||||
self.cbox, self.cbox.prefs, self.__plugin_manager.get_plugins())
|
self.cbox, self.cbox.prefs, self.__plugin_manager)
|
||||||
## publish plugin icons
|
|
||||||
self.icons = PluginIconHandler(self.__plugin_manager)
|
|
||||||
self.icons.exposed = True
|
|
||||||
## check, if a configuration partition has become available
|
## check, if a configuration partition has become available
|
||||||
self.cbox.prefs.prepare_partition()
|
self.cbox.prefs.prepare_partition()
|
||||||
|
|
||||||
|
@ -129,38 +135,49 @@ class WebInterfaceSites:
|
||||||
- reload all plugins and check their state (disabled or not)
|
- reload all plugins and check their state (disabled or not)
|
||||||
- reinitilize the datasets of all plugins
|
- reinitilize the datasets of all plugins
|
||||||
"""
|
"""
|
||||||
self.__plugin_manager = cryptobox.plugins.manage.PluginManager(
|
#TODO: in the long-term we should create a separate object that only
|
||||||
self.cbox, self.cbox.prefs["Locations"]["PluginDir"], self)
|
# contains the plugin handlers - this avoids some hassle of namespace
|
||||||
|
# conflicts - this object will be the cherrypy.server.root
|
||||||
|
# finish this for v0.4
|
||||||
for plugin in self.__plugin_manager.get_plugins():
|
for plugin in self.__plugin_manager.get_plugins():
|
||||||
if not plugin:
|
if not plugin:
|
||||||
continue
|
continue
|
||||||
plname = plugin.get_name()
|
plname = plugin.get_name()
|
||||||
## check if there are name conflicts: e.g. a local variable has the
|
## remove the old plugin handler and attach a new one
|
||||||
## same name as a plugin to be loaded -> skip these plugins
|
|
||||||
## if we do not check this here, nasty side effects may occour ...
|
|
||||||
try:
|
try:
|
||||||
|
## check if there are name conflicts: e.g. a local variable has
|
||||||
|
## the same name as a plugin to be loaded -> skip these plugins
|
||||||
|
## if we would not check this here, nasty effects could occour
|
||||||
prev_obj = getattr(self, plname)
|
prev_obj = getattr(self, plname)
|
||||||
if not callable(prev_obj) \
|
if not callable(prev_obj) or not prev_obj.exposed:
|
||||||
or not prev_obj.exposed:
|
## name conflict - see below
|
||||||
self.cbox.log.error("Skipped feature (%s) as its name"
|
raise NameError
|
||||||
+ " conflicts with a local variable - see"
|
## remove the plugin handler
|
||||||
+ " module cryptobox.web.sites" % plname)
|
delattr(self, plname)
|
||||||
## skip this plugin
|
except AttributeError:
|
||||||
continue
|
## "self" does not contain the given "plname" element
|
||||||
except (NameError, AttributeError):
|
## this is ok, as we are just cleaning up
|
||||||
## an attribute with the same name does not exist -> ok
|
pass
|
||||||
if plugin.is_enabled():
|
except NameError:
|
||||||
self.cbox.log.info("Plugin '%s' loaded" % plname)
|
## the attribute "exposed" of the element self."plname" does
|
||||||
## expose all features as URLs
|
## not exist - it seems, that we have a name conflict
|
||||||
setattr(self, plname, self.return_plugin_action(plugin))
|
self.cbox.log.error("Skipping feature (%s) as its" % plname
|
||||||
getattr(self, plname).exposed = True
|
+ " name conflicts with a local variable - see"
|
||||||
#TODO: check, if this really works
|
+ " module cryptobox.web.sites")
|
||||||
#for now the "stream_response" feature seems to be broken
|
## skip this plugin
|
||||||
#setattr(getattr(self, plname), "stream_respones", True)
|
continue
|
||||||
else:
|
## the old attribute was cleaned up - we can reinitialize it now
|
||||||
self.cbox.log.info("Plugin '%s' is disabled" % plname)
|
if plugin.is_enabled():
|
||||||
## remove the plugin, if it was active before
|
self.cbox.log.info("Plugin '%s' loaded" % plname)
|
||||||
setattr(self, plname, None)
|
## expose all features as URLs
|
||||||
|
setattr(self, plname, self.return_plugin_action(plugin))
|
||||||
|
getattr(self, plname).exposed = True
|
||||||
|
#TODO: check, if the stream_response feature really works
|
||||||
|
#for now the "stream_response" feature seems to be broken
|
||||||
|
#setattr(getattr(self, plname), "stream_respones", True)
|
||||||
|
else:
|
||||||
|
self.cbox.log.info("Plugin '%s' is disabled" % plname)
|
||||||
|
## nothing else has to be done
|
||||||
|
|
||||||
|
|
||||||
## sub pages requiring authentication may not be defined above
|
## sub pages requiring authentication may not be defined above
|
||||||
|
@ -273,7 +290,8 @@ class WebInterfaceSites:
|
||||||
""" returns a function that is suitable for handling a cherrypy
|
""" returns a function that is suitable for handling a cherrypy
|
||||||
page request
|
page request
|
||||||
"""
|
"""
|
||||||
def handler(self, weblang="", device=None, help="0", redirect=None, message_keep=None, **args):
|
def handler(self, weblang="", device=None, help="0", redirect=None,
|
||||||
|
message_keep=None, **args):
|
||||||
"""this function handles a cherrypy page request
|
"""this function handles a cherrypy page request
|
||||||
"""
|
"""
|
||||||
plugin.reset()
|
plugin.reset()
|
||||||
|
@ -323,10 +341,17 @@ class WebInterfaceSites:
|
||||||
else:
|
else:
|
||||||
## some non-volume plugins change the internal state of other
|
## some non-volume plugins change the internal state of other
|
||||||
## plugins - e.g.: plugin_manager
|
## plugins - e.g.: plugin_manager
|
||||||
|
## if we do not call __load_plugins now, then it is possible
|
||||||
|
## to call a plugin directly after disabling it (only once)
|
||||||
|
self.__load_plugins()
|
||||||
self.__dataset.set_plugin_data()
|
self.__dataset.set_plugin_data()
|
||||||
## default page for non-volume plugins is the disk selection
|
## default page for non-volume plugins is the disk selection
|
||||||
if not next_template:
|
if not next_template:
|
||||||
next_template = { "plugin":"disks", "values":{} }
|
next_template = { "plugin":"disks", "values":{} }
|
||||||
|
#TODO: there is a lot of piece-by-piece updating around here
|
||||||
|
# for v0.4 we should just call __reset_dataset - but this would
|
||||||
|
# require to store the currently changed dataset values (e.g.i
|
||||||
|
# weblang) somewhere else to not override it
|
||||||
## some non-volume plugins may change the state of containers
|
## some non-volume plugins may change the state of containers
|
||||||
## the mount plugin may change the number of active disks - for the logo
|
## the mount plugin may change the number of active disks - for the logo
|
||||||
self.__dataset.set_containers_state()
|
self.__dataset.set_containers_state()
|
||||||
|
@ -412,8 +437,7 @@ class WebInterfaceSites:
|
||||||
## check an environment setting - this is quite common behind proxies
|
## check an environment setting - this is quite common behind proxies
|
||||||
if os.environ.has_key("HTTPS"):
|
if os.environ.has_key("HTTPS"):
|
||||||
return True
|
return True
|
||||||
## this arbitrarily chosen header must be documented in README.proxy
|
## this arbitrarily chosen header is documented in README.proxy
|
||||||
#TODO: check http://jamesthornton.com/writing/openacs-pound.html for this
|
|
||||||
if cherrypy.request.headers.has_key("X-SSL-Request") \
|
if cherrypy.request.headers.has_key("X-SSL-Request") \
|
||||||
and (cherrypy.request.headers["X-SSL-Request"] == "1"):
|
and (cherrypy.request.headers["X-SSL-Request"] == "1"):
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in a new issue