Plugin Manager

Manages plugin discovery, loading, configuration, lifecycle, and event dispatch.

This module is central to the plugin architecture of the Bedrock Server Manager. The PluginManager class handles all aspects of plugin interaction, including:

  • Locating plugin files in designated directories.

  • Reading and writing plugin configurations (e.g., enabled status, metadata) from/to a JSON file (typically plugins.json).

  • Validating plugins (e.g., ensuring they subclass PluginBase and have a version attribute).

  • Dynamically loading valid and enabled plugins.

  • Managing the lifecycle of plugins (e.g., calling on_load, on_unload event hooks).

  • Dispatching application-wide events to all loaded plugins.

  • Facilitating custom inter-plugin event communication. Custom event names must follow a ‘namespace:event_name’ format (e.g., myplugin:data_updated).

  • Providing a mechanism to reload all plugins.

class bedrock_server_manager.plugins.plugin_manager.PluginManager(settings: Settings)

Bases: object

Manages the discovery, loading, aconfiguration, and lifecycle of all plugins.

This class is the core of the plugin system. It scans for plugins, manages their configuration in plugins.json, loads enabled plugins, and dispatches various events to them.

set_app_context(app_context: AppContext)

Sets the application context for the plugin manager.

load_plugins()

Discovers, validates, and loads all enabled plugins.

This method orchestrates the entire plugin loading process:

  1. Calls _synchronize_config_with_disk() to ensure the plugin configuration (self.plugin_config) is up-to-date with files on disk and that all plugin entries are valid.

  2. Clears any previously loaded plugin instances from self.plugins. This is important for supporting the reload() functionality.

  3. Iterates through the synchronized self.plugin_config:

    1. If a plugin is marked as enabled in its configuration and has a valid version:

      1. Finds the plugin’s file path using _find_plugin_path().

      2. Loads the plugin class from the file using _get_plugin_class_from_path().

      iii.If class loading is successful, instantiates the plugin class.

      The instance is provided with its name, a api_bridge.PluginAPI instance (for core interaction), and a dedicated logging.Logger instance.

      1. Appends the new plugin instance to the self.plugins list.

      2. Dispatches the on_load event to the newly loaded plugin instance via dispatch_event().

Errors during the loading or instantiation of individual plugins are logged, and the process continues with other plugins.

unload_plugins()

Unloads all currently active plugins.

This method provides a way to refresh the plugin system without restarting the entire application. It involves:

  1. Dispatching the on_unload event to all currently loaded plugins (via dispatch_event()).

  2. Clearing all registered custom event listeners from self.custom_event_listeners (as the plugins that registered them are being unloaded).

get_html_render_routes() List[Dict[str, str]]

Collects routes from all plugin routers that are tagged for HTML rendering.

Returns:

A list of dictionaries, where each dictionary

contains ‘name’ and ‘path’ for a tagged route.

Return type:

List[Dict[str, str]]

register_plugin_event_listener(event_name: str, callback: Callable, listening_plugin_name: str)

Registers a callback function from a plugin to listen for a custom event.

Parameters:
  • event_name (str) – The name of the custom event to listen for. Must be in the format ‘namespace:event_name’ (e.g., myplugin:custom_signal). Validation is performed by _is_valid_custom_event_name().

  • callback (Callable) – The function/method in the listening plugin that will be called when the specified event is triggered.

  • listening_plugin_name (str) – The name of the plugin registering the listener. Used for logging and context.

trigger_custom_plugin_event(event_name: str, triggering_plugin_name: str, *args, **kwargs)

Triggers a custom event, invoking all registered listener callbacks.

This method manages the dispatch of custom events sent by plugins (or via the external API trigger). It includes re-entrancy protection using _custom_event_context (a threading.local stack) to prevent infinite loops if a listener, in turn, triggers the same event.

The _triggering_plugin keyword argument, containing the name of the plugin (or “external_api_trigger”) that initiated the event, is automatically added to the kwargs passed to listener callbacks.

Parameters:
  • event_name (str) – The name of the custom event being triggered. Must be in the format ‘namespace:event_name’ (e.g., myplugin:data_updated). Validated by _is_valid_custom_event_name().

  • triggering_plugin_name (str) – The name of the plugin that initiated this event.

  • *args (Any) – Positional arguments to pass to the listener callbacks.

  • **kwargs (Any) – Keyword arguments to pass to the listener callbacks.

reload()

Unloads all currently active plugins and then reloads all plugins.

This method provides a way to refresh the plugin system without restarting the entire application. It involves:

  1. Dispatching the on_unload event to all currently loaded plugins (via dispatch_event()).

  2. Clearing all registered custom event listeners from self.custom_event_listeners (as the plugins that registered them are being unloaded).

  3. Calling load_plugins() to re-run the discovery, synchronization, and loading process for all plugins based on the current disk state and plugins.json configuration.

dispatch_event(target_plugin: PluginBase, event: str, *args, **kwargs)

Dispatches a single standard application event to a specific plugin instance.

This method attempts to call the method corresponding to event on the target_plugin instance, passing *args and **kwargs. If the target_plugin does not have a method for the specified event, it is logged at DEBUG level and skipped. Any exceptions raised by the plugin’s event handler are caught and logged as errors.

Parameters:
  • target_plugin (PluginBase) – The plugin instance to which the event should be dispatched.

  • event (str) – The name of the event method to call on the plugin (e.g., “on_load”, “before_server_start”).

  • *args (Any) – Positional arguments to pass to the event handler method.

  • **kwargs (Any) – Keyword arguments to pass to the event handler method.

trigger_event(event: str, *args: Any, **kwargs: Any)

Triggers a standard application event on all loaded plugins.

This method iterates through all currently loaded and active plugins (in self.plugins) and calls dispatch_event() for each one. It includes a granular re-entrancy protection mechanism using _event_context (a threading.local stack) and event instance keys generated by _generate_event_key() (based on EVENT_IDENTITY_KEYS). This prevents infinite loops if an event handler triggers an action that causes the same specific event instance to be dispatched again within the same call stack.

Parameters:
  • event (str) – The name of the event to trigger (e.g., “before_server_start”).

  • *args (Any) – Positional arguments to pass to each plugin’s event handler.

  • **kwargs (Any) – Keyword arguments to pass to each plugin’s event handler. Some of these may be used by _generate_event_key() to identify the event instance.

trigger_guarded_event(event: str, *args, **kwargs)

Triggers a standard application event only if not in a guarded child process.

This method checks for the presence of the GUARD_VARIABLE environment variable (using os.environ.get). If this variable is set (indicating the current process might be a specially managed child process, like one launched for detached server operation, where certain global events should not be re-triggered), the event dispatch is skipped. Otherwise, it calls trigger_event().

Parameters:
  • event (str) – The name of the event to trigger.

  • *args (Any) – Positional arguments for the event handler.

  • **kwargs (Any) – Keyword arguments for the event handler.