Gamend.Hooks.PluginManager (gamend_core v1.0.1296)

Copy Markdown View Source

Loads and manages hook plugins shipped as OTP applications under modules/plugins/*.

Each plugin is expected to be a directory named after the OTP app name (e.g. my_game_hook) containing:

modules/plugins/my_game_hook/
  ebin/my_game_hook.app
  ebin/Elixir.Gamend.Modules.MyGameHook.beam
  priv/**
  deps/*/ebin/*.beam
  deps/*/priv/**

The plugin's .app env must include the key :hooks_module, whose value is either a charlist or string module name like 'Elixir.Gamend.Modules.MyGameHook'.

This manager is intentionally dependency-free: it only adds ebin directories to the code path and uses Application.load/1 + Application.ensure_all_started/1.

Summary

Functions

How long a hook call may run, in ms: call_timeout_in_transaction_ms inside a Repo transaction, call_timeout_ms otherwise.

Returns a specification to start this module under a supervisor.

Loads one plugin from disk again and runs its after_startup/0, the counterpart of suspend/1. Returns the plugin (its status says whether it started), or nil when the manager is not running or skips the name.

Stops and unloads one plugin, leaving the others running. Returns true when the manager had it (loaded or failed), false when it did not or the manager is not running.

Types

plugin_app()

@type plugin_app() :: atom()

plugin_name()

@type plugin_name() :: String.t()

Functions

call_rpc(plugin, fn_name, args, opts \\ [])

@spec call_rpc(plugin_name(), String.t(), list(), keyword()) ::
  {:ok, any()} | {:error, term()}

call_timeout_ms()

@spec call_timeout_ms() :: pos_integer()

How long a hook call may run, in ms: call_timeout_in_transaction_ms inside a Repo transaction, call_timeout_ms otherwise.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

hook_modules()

@spec hook_modules() :: [{plugin_name(), module()}]

list()

lookup(name)

@spec lookup(plugin_name()) ::
  {:ok, Gamend.Hooks.PluginManager.Plugin.t()} | {:error, term()}

plugins_dir()

@spec plugins_dir() :: String.t()

reload()

@spec reload() :: [Gamend.Hooks.PluginManager.Plugin.t()]

reload_and_after_startup()

@spec reload_and_after_startup() :: %{
  plugins: [Gamend.Hooks.PluginManager.Plugin.t()],
  after_startup: map()
}

resume(name)

Loads one plugin from disk again and runs its after_startup/0, the counterpart of suspend/1. Returns the plugin (its status says whether it started), or nil when the manager is not running or skips the name.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

suspend(name)

@spec suspend(plugin_name()) :: boolean()

Stops and unloads one plugin, leaving the others running. Returns true when the manager had it (loaded or failed), false when it did not or the manager is not running.

The in-process build (Gamend.Hooks.PluginBuilder) calls this before it compiles the plugin in this VM. The compiler treats a module that is already loaded as available, so a module compiled against a sibling that is still loaded would take that sibling's old macros and structs; unloading the plugin first makes the build see only its own new code. resume/1 loads it back.