Screen Manager & PubSub

Copy Markdown View Source

Dala provides two powerful features for inter-screen communication and screen lifecycle management:

  1. Screen Manager - Auto-registers screens with unique IDs, allows querying by name/id/pid
  2. PubSub - Lightweight publish-subscribe for broadcasting messages between screens

Screen Manager

The Dala.Screen.Manager tracks all active screens in your application. Screens auto-register when started and unregister when they terminate.

Features

  • Auto-registration: Screens register themselves automatically on start
  • Unique IDs: Each screen gets a sequential integer ID
  • Multiple lookup methods: Find screens by ID, name, or PID
  • List all screens: Get a snapshot of all active screens

API

Dala.Screen.Manager

# Register a screen (called automatically by Dala.Screen)
Dala.Screen.Manager.register(id, name, pid, module)

# Unregister a screen (called automatically on terminate)
Dala.Screen.Manager.unregister(pid)

# Generate a unique screen ID
Dala.Screen.Manager.next_id()

# List all registered screens
Dala.Screen.Manager.list()
# => [%{id: 0, name: :home, pid: #PID<0.123.0>, module: MyApp.HomeScreen}]

# Send a message to a screen by identifier
Dala.Screen.Manager.dispatch(:home, {:update, data})
Dala.Screen.Manager.dispatch(0, {:update, data})
Dala.Screen.Manager.dispatch(pid, {:update, data})

Dala.Screen

# Send a message to any screen
Dala.Screen.Screen.dispatch(:home, {:update, data})
Dala.Screen.Screen.dispatch(0, {:update, data})
Dala.Screen.Screen.dispatch(pid, {:update, data})

# List all screens
Dala.Screen.list()
# => [%{id: 0, name: :home, pid: #PID<0.123.0>, module: MyApp.HomeScreen}]

Usage Example

defmodule MyApp.HomeScreen do
  use Dala.Spark.Dsl

  dala do
    screen name: :home do
      column do
        text "Home Screen"
      end
    end
  end

  def handle_info({:update, data}, socket) do
    # Handle messages from other screens
    {:noreply, Dala.Socket.assign(socket, :data, data)}
  end
end

# From another module or screen
defmodule MyApp.OtherScreen do
  use Dala.Spark.Dsl

  dala do
    screen name: :other do
      column do
        text "Other Screen"
        button "Send Update", on_tap: :send_update
      end
    end
  end

  def handle_event(:send_update, _params, socket) do
    # Send message to home screen by name
    Dala.Screen.Screen.dispatch(:home, {:update, %{value: 42}})
    {:noreply, socket}
  end
end

PubSub

Dala.PubSub provides a lightweight publish-subscribe system using Elixir's built-in Registry. No Redis, no adapters — just fast local pubsub.

Features

  • Simple API: Subscribe, unsubscribe, broadcast
  • Local-only: Fast in-process communication
  • No dependencies: Uses Elixir's Registry
  • Broadcast exclusion: broadcast_from/4 excludes the sender

API

# Start a pubsub instance (in your supervision tree)
{Dala.PubSub, name: MyApp.PubSub}

# Subscribe to a topic
Dala.PubSub.subscribe(MyApp.PubSub, "user:123")

# Unsubscribe from a topic
Dala.PubSub.unsubscribe(MyApp.PubSub, "user:123")

# Broadcast to all subscribers
Dala.PubSub.broadcast(MyApp.PubSub, "user:123", {:message, data})

# Broadcast excluding the sender
Dala.PubSub.broadcast_from(MyApp.PubSub, self(), "user:123", {:message, data})

# Get subscriber count
Dala.PubSub.subscriber_count(MyApp.PubSub, "user:123")

Usage Example

defmodule MyApp do
  use Application

  def start(_type, _args) do
    children = [
      {Dala.PubSub, name: MyApp.PubSub}
    ]

    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

defmodule MyApp.ChatScreen do use Dala.Spark.Dsl

dala do

attribute :messages, :list, default: []

screen name: :chat do
  column do
    text "Chat Room"
    button "Send", on_tap: :send_message
  end
end

end

def mount(_params, _session, socket) do

# Subscribe to chat room on mount
Dala.PubSub.subscribe(MyApp.PubSub, "chat:room:123")
{:ok, socket}

end

def handle_info({:message, text}, socket) do

# Handle incoming messages
messages = socket.assigns.messages ++ [text]
{:noreply, Dala.Socket.assign(socket, :messages, messages)}

end

def handle_event(:send_message, _params, socket) do

# Broadcast message to all subscribers
Dala.PubSub.broadcast(MyApp.PubSub, "chat:room:123", {:message, "Hello"})
{:noreply, socket}

end end


### Spark DSL Integration

You can also declare PubSub subscriptions declaratively in your screens:

defmodule MyApp.ChatScreen do use Dala.Spark.Dsl

dala do

attribute :messages, :list, default: []

pubsub do
  subscribe "chat:room:123", on_message: :handle_chat
end

screen name: :chat do
  column do
    text "Messages: @messages"
  end
end

end

def handle_chat({:message, text}, socket) do

messages = socket.assigns.messages ++ [text]
{:noreply, Dala.Socket.assign(socket, :messages, messages)}

end end


## Comparison with Phoenix.PubSub

| Feature | Phoenix.PubSub | Dala.PubSub |
|---------|---------------|-------------|
| Adapters | PG2, Redis | None (Registry only) |
| Distribution | Yes (multi-node) | No (local only) |
| Dependencies | phoenix_pubsub | None |
| API | Full-featured | Minimal |
| Use case | Multi-server apps | Single-device apps |

Dala.PubSub is designed for single-device applications where you need fast, simple pubsub without the overhead of distributed systems. For multi-node scenarios, use Phoenix.PubSub with the PG2 or Redis adapter.