Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/core/global_registry.ex
defmodule Raxol.Core.GlobalRegistry do
@moduledoc """
Unified registry interface consolidating different registry patterns across Raxol.
This module provides a single interface for:
- Terminal session registry
- Plugin registry
- Component registry
- Theme/palette registry
- Command registry
## Usage
### Terminal Sessions
UnifiedRegistry.register(:sessions, session_id, session_data)
sessions = UnifiedRegistry.list(:sessions)
### Plugins
UnifiedRegistry.register(:plugins, plugin_id, plugin_metadata)
plugins = UnifiedRegistry.list(:plugins)
### Commands
UnifiedRegistry.register(:commands, command_name, command_handler)
commands = UnifiedRegistry.search(:commands, pattern)
"""
use Raxol.Core.Behaviours.BaseManager
alias Raxol.Core.Runtime.Log
@type registry_type ::
:sessions | :plugins | :commands | :themes | :components
@type entry_id :: String.t() | atom()
@type entry_data :: any()
defmodule RegistryBehaviour do
@moduledoc """
Behaviour for unified registry operations.
"""
@type registry_type ::
:sessions | :plugins | :commands | :themes | :components
@type entry_id :: String.t() | atom()
@type entry_data :: any()
@callback register(registry_type(), entry_id(), entry_data()) ::
:ok | {:error, term()}
@callback unregister(registry_type(), entry_id()) :: :ok | {:error, term()}
@callback lookup(registry_type(), entry_id()) ::
{:ok, entry_data()} | {:error, :not_found}
@callback list(registry_type()) :: [entry_data()]
@callback count(registry_type()) :: non_neg_integer()
@callback search(registry_type(), String.t()) :: [entry_data()]
end
@behaviour RegistryBehaviour
defstruct [
:sessions,
:plugins,
:commands,
:themes,
:components,
:config
]
# Client API
@doc """
Registers an entry in the specified registry.
"""
@impl RegistryBehaviour
def register(type, id, data) do
GenServer.call(__MODULE__, {:register, type, id, data})
end
@doc """
Unregisters an entry from the specified registry.
"""
@impl RegistryBehaviour
def unregister(type, id) do
GenServer.call(__MODULE__, {:unregister, type, id})
end
@doc """
Looks up an entry in the specified registry.
"""
@impl RegistryBehaviour
def lookup(type, id) do
GenServer.call(__MODULE__, {:lookup, type, id})
end
@doc """
Lists all entries in the specified registry.
"""
@impl RegistryBehaviour
def list(type) do
GenServer.call(__MODULE__, {:list, type})
end
@doc """
Counts entries in the specified registry.
"""
@impl RegistryBehaviour
def count(type) do
GenServer.call(__MODULE__, {:count, type})
end
@doc """
Searches for entries matching a pattern in the specified registry.
"""
@impl RegistryBehaviour
def search(type, pattern) do
GenServer.call(__MODULE__, {:search, type, pattern})
end
@doc """
Filters entries by a custom function.
"""
def filter(type, filter_fn) when is_function(filter_fn, 1) do
GenServer.call(__MODULE__, {:filter, type, filter_fn})
end
@doc """
Gets registry statistics.
"""
def stats do
GenServer.call(__MODULE__, :stats)
end
@doc """
Bulk operations for efficiency.
"""
def bulk_register(type, entries) when is_list(entries) do
GenServer.call(__MODULE__, {:bulk_register, type, entries})
end
def bulk_unregister(type, ids) when is_list(ids) do
GenServer.call(__MODULE__, {:bulk_unregister, type, ids})
end
# Registry-specific convenience functions
@doc """
Session registry operations.
"""
def register_session(session_id, session_data) do
register(:sessions, session_id, session_data)
end
def unregister_session(session_id) do
unregister(:sessions, session_id)
end
def lookup_session(session_id) do
lookup(:sessions, session_id)
end
def list_sessions do
list(:sessions)
end
@doc """
Plugin registry operations.
"""
def register_plugin(plugin_id, plugin_metadata) do
register(:plugins, plugin_id, plugin_metadata)
end
def unregister_plugin(plugin_id) do
unregister(:plugins, plugin_id)
end
def lookup_plugin(plugin_id) do
lookup(:plugins, plugin_id)
end
def list_plugins do
list(:plugins)
end
@doc """
Command registry operations.
"""
def register_command(command_name, command_handler) do
register(:commands, command_name, command_handler)
end
def unregister_command(command_name) do
unregister(:commands, command_name)
end
def lookup_command(command_name) do
lookup(:commands, command_name)
end
def list_commands do
list(:commands)
end
def search_commands(pattern) do
search(:commands, pattern)
end
# GenServer Implementation
@impl true
def init_manager(opts) do
config = Keyword.get(opts, :config, %{})
state = %__MODULE__{
sessions: %{},
plugins: %{},
commands: %{},
themes: %{},
components: %{},
config: config
}
Log.info("Unified Registry started")
{:ok, state}
end
@impl true
def handle_manager_call({:register, type, id, data}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
updated_registry =
Map.put(registry, id, %{
id: id,
data: data,
registered_at: System.monotonic_time(:millisecond),
metadata: %{}
})
new_state = put_registry(state, type, updated_registry)
{:reply, :ok, new_state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:unregister, type, id}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
updated_registry = Map.delete(registry, id)
new_state = put_registry(state, type, updated_registry)
{:reply, :ok, new_state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:lookup, type, id}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
case Map.get(registry, id) do
nil -> {:reply, {:error, :not_found}, state}
entry -> {:reply, {:ok, entry.data}, state}
end
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:list, type}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
entries = registry |> Map.values() |> Enum.map(& &1.data)
{:reply, entries, state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:count, type}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
{:reply, map_size(registry), state}
{:error, _reason} ->
{:reply, 0, state}
end
end
@impl true
def handle_manager_call({:search, type, pattern}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
regex = Regex.compile!(pattern, [:caseless])
matching_entries =
registry
|> Map.values()
|> Enum.filter(fn entry ->
id_str = to_string(entry.id)
Regex.match?(regex, id_str)
end)
|> Enum.map(& &1.data)
{:reply, matching_entries, state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:filter, type, filter_fn}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
matching_entries =
registry
|> Map.values()
|> Enum.filter(fn entry -> filter_fn.(entry.data) end)
|> Enum.map(& &1.data)
{:reply, matching_entries, state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call(:stats, _from, state) do
stats = %{
sessions: map_size(state.sessions),
plugins: map_size(state.plugins),
commands: map_size(state.commands),
themes: map_size(state.themes),
components: map_size(state.components),
total_entries:
map_size(state.sessions) + map_size(state.plugins) +
map_size(state.commands) + map_size(state.themes) +
map_size(state.components)
}
{:reply, stats, state}
end
@impl true
def handle_manager_call({:bulk_register, type, entries}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
now = System.monotonic_time(:millisecond)
updated_registry =
Enum.reduce(entries, registry, fn {id, data}, acc ->
Map.put(acc, id, %{
id: id,
data: data,
registered_at: now,
metadata: %{}
})
end)
new_state = put_registry(state, type, updated_registry)
{:reply, {:ok, length(entries)}, new_state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
@impl true
def handle_manager_call({:bulk_unregister, type, ids}, _from, state) do
case get_registry(state, type) do
{:ok, registry} ->
updated_registry =
Enum.reduce(ids, registry, fn id, acc ->
Map.delete(acc, id)
end)
new_state = put_registry(state, type, updated_registry)
{:reply, {:ok, length(ids)}, new_state}
{:error, reason} ->
{:reply, {:error, reason}, state}
end
end
# Private Helper Functions
defp get_registry(state, type) do
case type do
:sessions -> {:ok, state.sessions}
:plugins -> {:ok, state.plugins}
:commands -> {:ok, state.commands}
:themes -> {:ok, state.themes}
:components -> {:ok, state.components}
_ -> {:error, :unknown_registry_type}
end
end
defp put_registry(state, type, registry) do
case type do
:sessions -> %{state | sessions: registry}
:plugins -> %{state | plugins: registry}
:commands -> %{state | commands: registry}
:themes -> %{state | themes: registry}
:components -> %{state | components: registry}
end
end
end