Skip to content

Daemon Startup and State

Joseph Chacko edited this page Jul 22, 2026 · 2 revisions

Daemon Startup & State Initialization

Relevant source files

The following files were used as context for generating this wiki page:

This page details the lifecycle of the aurora-daemon from the initial execution of the binary to the point where it is ready to handle client requests. The startup sequence involves daemonization, initializing audio hardware, opening the persistent database, indexing the music library, and launching several background management threads.

Entry Point: main() and Daemonization

The main() function serves as the initial entry point. Its primary responsibility is to detach the process from the terminal and initialize the asynchronous runtime.

  • Tracing Initialization: The system starts tracing_subscriber for logging daemon/src/main.rs:29-29.
  • Daemonization: If no command-line arguments are provided, the process uses the daemonize crate to fork into the background daemon/src/main.rs:31-40. It sets up a PID file at /tmp/aurora-daemon.pid and redirects standard output to /tmp/aurora-daemon.out daemon/src/main.rs:24-26.
  • Runtime Setup: A multi-threaded tokio runtime is built with I/O and time drivers enabled to execute the async_main() function daemon/src/main.rs:42-48.

Signal Handling

Immediately upon entering async_main(), a dedicated thread is spawned to monitor TERM_SIGNALS (SIGINT, SIGTERM). When a signal is received, it performs cleanup by deleting the Unix socket and PID files before exiting daemon/src/main.rs:52-63.

Sources: daemon/src/main.rs:24-63

State Initialization Pipeline

The core of the daemon is the StateStruct, wrapped in an Arc<Mutex<...>> to allow shared access across multiple tasks and threads daemon/src/types/mod.rs:10-10.

1. Audio Engine Setup

The daemon uses the rodio crate for audio playback. It opens the default output stream and creates a Sink connected to the mixer daemon/src/main.rs:65-69. This sink is later stored in the StateStruct to control playback daemon/src/types/state_impl/mod.rs:20-20.

2. Database & Library Indexing

  • Database: The daemon opens a connection to the SQLite database via helpers::db::open() daemon/src/main.rs:71-71.
  • Indexing: It identifies the user's music directory (defaulting to ~/Music) and calls helpers::build_index to scan the filesystem and sync metadata with the database daemon/src/main.rs:73-76.
  • Persistence Loading: Play history and "liked" song IDs are loaded from the database into memory-efficient structures (VecDeque and HashSet respectively) daemon/src/main.rs:77-78.

3. State Construction

The StateStruct is instantiated with the gathered components:

Field Type Description
index SongIndex A HashMap mapping Uuid to SongMeta daemon/src/types/mod.rs:9-9.
sink Arc<Sink> The Rodio audio sink daemon/src/types/state_impl/mod.rs:20-20.
theme Theme Loaded from config.toml via theme_thread::get_config() daemon/src/main.rs:87-87.
db Db Thread-safe handle to the SQLite database daemon/src/types/state_impl/mod.rs:29-29.

Sources: daemon/src/main.rs:65-94, daemon/src/types/state_impl/mod.rs:16-30

Startup Logic Flow

The following diagram illustrates the sequence of operations during the async_main execution.

Startup Sequence Diagram

sequenceDiagram
    participant M as async_main
    participant A as Audio Hardware
    participant D as SQLite (Db)
    participant S as StateStruct
    participant T as Background Threads

    M->>M: Spawn Signal Handler Thread
    M->>A: rodio::OutputStreamBuilder::open_default_stream()
    M->>A: rodio::Sink::connect_new()
    M->>D: helpers::db::open()
    M->>D: helpers::build_index(music_dir, db)
    M->>D: helpers::load_history() / load_liked()
    M->>S: Construct StateStruct (Arc<Mutex<...>>)
    M->>T: tokio::spawn(watcher_thread)
    M->>T: tokio::spawn(file_watcher_thread)
    M->>T: tokio::spawn(mpris_thread)
    M->>T: tokio::spawn(theme_thread)
    M->>M: UnixListener::bind(/tmp/aurora-daemon.sock)
Loading

Sources: daemon/src/main.rs:51-112

Background Thread Spawning

Once the StateStruct is initialized, the daemon spawns four critical background tasks using tokio::spawn. Each task receives a clone of the Arc<State> to interact with the system status.

  1. watcher_thread: Monitors the rodio::Sink to detect when a track finishes, triggering auto-advance to the next song in the queue daemon/src/main.rs:97-97.
  2. file_watcher_thread: Watches the filesystem for changes in the music directory to trigger incremental re-indexing daemon/src/main.rs:100-100.
  3. mpris_thread: Provides D-Bus integration, allowing Linux desktop environments to control playback daemon/src/main.rs:103-103.
  4. theme_thread: Watches for changes in the config.toml file to update the UI theme across all connected clients in real-time daemon/src/main.rs:106-106.

Sources: daemon/src/main.rs:96-106

Socket Server Loop

The final stage of startup is the listener loop. The daemon binds to the Unix domain socket at /tmp/aurora-daemon.sock daemon/src/main.rs:108-112.

Connection Handling

When a client (like aurora-player) connects:

  1. The socket is split into an OwnedReadHalf and an OwnedWriteHalf daemon/src/main.rs:117-117.
  2. The writer is wrapped in Arc<Mutex<...>> and added to state.clients so the daemon can broadcast status updates daemon/src/main.rs:118-122.
  3. A new tokio task is spawned to run handlers::handle_client, which processes incoming Request objects daemon/src/main.rs:126-132.
  4. Upon client disconnection, the task removes the client's writer from the state.clients vector daemon/src/main.rs:133-141.

Code Entity Mapping

graph TD
    subgraph "Code Entity Space"
        MAIN["main() / async_main()"]
        STATE["StateStruct"]
        LISTENER["UnixListener"]
        HANDLER["handle_client()"]
        SINK["rodio::Sink"]
    end

    subgraph "Natural Language Space"
        START["Process Entry"]
        MEM["Shared Global State"]
        IPC["Unix Socket Server"]
        REQ["Request Processing"]
        AUDIO["Audio Output"]
    end

    START --> MAIN
    MEM --> STATE
    IPC --> LISTENER
    REQ --> HANDLER
    AUDIO --> SINK

    MAIN -- "initializes" --> STATE
    MAIN -- "starts" --> LISTENER
    LISTENER -- "spawns" --> HANDLER
    STATE -- "controls" --> SINK
Loading

Sources: daemon/src/main.rs:115-143, daemon/src/types/state_impl/mod.rs:16-30

Clone this wiki locally