rustpbx Documentation

repository·main·Indexed 20 days ago

https://github.com/restsend/rustpbx

A high-performance, software-defined, AI-native SIP PBX and SIP Proxy implementation in Rust (v0.4.13). It externalizes call control via HTTP, WebSockets, and Webhooks, featuring a Real-time WebSocket Interface (RWI) for in-call control of media, recordings, and queues. The system includes a modular Addons architecture for plugin integration, a media bridging layer for WebRTC and RTP, and a set of HTTP utility tools for JSON fetching and streaming.

Tokens
113.6K
Snippets
332
Records
439
Agent score
72%

What's inside rustpbx

  1. Overview of SipFlow Subsystem

    main

    SipFlow is the SIP signaling and RTP recording subsystem within rustpbx. It is responsible for capturing SIP/RTP packets and providing features such as signaling replay, WAV export from RTP, and media quality statistics.

    It supports three primary operational modes:

    1. Embedded Mode: Integrated directly into callrecord using a batch writer and object pool.
    2. Standalone Server Mode: Operates as a separate binary (src/bin/sipflow.rs) receiving data via UDP and exposing an HTTP API (/flow, /media, /health).
    3. Remote Cluster Mode: Uses a RemoteBackend where nodes send data via UDP to a dedicated SipFlow cluster using Jump Consistent Hashing for node selection.
  2. Overview of RWI (Real-time WebSocket Interface) channels

    main

    RustPBX provides real-time event streaming for calls, IVR, recordings, queues, agents, and extensions via the RWI. Developers can choose between two primary channels depending on their use case:

    1. WebSocket subscription: Use ws(s)://<host>/rwi/v1 for real-time, bidirectional interactions such as building bots, softphones, or live dashboards.
    2. Webhook callback: Use HTTP POST for asynchronous notifications to external systems like CRMs, recording storage, or analytics engines.
    | Channel | Protocol | Use Case |
    |---------|----------|----------|
    | **WebSocket subscription** | `ws(s)://<host>/rwi/v1` | Real-time bidirectional interaction (bots, softphones, dashboards) |
    | **Webhook callback** | HTTP POST | Async notifications (CRM, recording systems, analytics) |
  3. Override Queue Settings via URI Query Parameters

    main

    When transferring a call to a queue using the queue:<name> syntax, you can append query parameters to override the queue's configuration at runtime.

    • ?return_ivr=<name>: Overrides the fallback action to transfer to a specific IVR instead of the configured fallback.
    • ?target=<value>: Overrides the configured agent targets. Supports SIP URIs or skillgroup:<id> (resolved via AgentRegistry). Multiple &target= parameters can be used for sequential dialing.

    Example usage: queue:support?target=skillgroup:sales&return_ivr=main_menu

    # Single skill group
    queue:support?target=skillgroup:sales
    
    # Single SIP agent
    queue:support?target=sip:agent@pbx.com
    
    # Multiple targets (sequential)
    queue:support?target=skillgroup:sales&target=skillgroup:support
    
    # Combined usage
    queue:support?target=skillgroup:sales&return_ivr=main_menu
  4. Use i18n filters in templates

    main

    When using ConsoleState::render, the following filters are available in the template engine to handle translations:

    • t(key): A simple filter that takes a translation key and returns the string in the current locale.
    • tvars(key, vars): A filter that takes a translation key and a JSON object of variables. It performs variable interpolation (e.g., {{name}}).

    Additionally, the following variables are injected into the template context:

    • locale: The current locale string.
    • t: The entire nested translation object for the current locale.
    • available_locales: A list of LocaleInfo objects for all supported languages.
  5. Configure User Authentication Backends

    main

    RustPBX uses a chain of backends for user authentication and retrieval, configured via proxy.user_backends. Backends are queried sequentially; if a user is not found in the first backend, the next one in the list is checked.

    Management: Backends can be managed through the Web Console under Settings > Proxy Settings, which includes a Test feature to verify connectivity and logic.

    Supported backend types include:

    • memory: Static user definitions.
    • database: Users loaded from the configured SQL database.
    • http: Remote authentication via an external web service.
    • plain: Users loaded from a text file.
    • extension: Short-lived, dynamic extensions.
    • jwt: Local JWT validation (highest priority in the auth chain).
    [[proxy.user_backends]]
    type = "memory"
    
    [[proxy.user_backends.users]]
    username = "1001"
    password = "secret-password"
    realm = "example.com"
    display_name = "Alice"
    enabled = true
    allow_guest_calls = false
  6. Understand the Seat Replacement Event Sequence

    main

    When a conference seat is being replaced, the following sequence of events is emitted to ensure a successful transition:

    1. conference_seat_replace_started
    2. conference_member_left (the old member leaves)
    3. conference_member_joined (the new member joins)
    4. conference_seat_replace_succeeded
  7. How the RustPBX Addons architecture works

    main

    The RustPBX Addons system is a modular plugin architecture designed to integrate both free and commercial features. It relies on four core components:

    1. Addon Trait: The interface defining the lifecycle, routing, and UI injection capabilities of a plugin.
    2. Addon Manager (Registry): Handles loading, initializing, and aggregating routes and UI elements from all active plugins.
    3. Feature Flags: Uses Cargo.toml features to control which plugins are compiled into the binary.
    4. License System: A runtime mechanism used by commercial plugins to verify authorization.

    This decoupling allows developers to manage plugins as git submodules and control their availability via compilation flags.

    // Typical directory structure for an addon
    src/
      addons/
        mod.rs          # Addon Trait and Manager
        registry.rs     # Plugin registry
        acme/           # [Built-in] Free plugin
        voicemail/      # [Submodule] Commercial plugin
        ...
  8. Understand RWI event dispatch methods

    main

    RustPBX uses different dispatch methods to route events to the appropriate recipients:

    • call_owner: Sends fine-grained, per-call events to the specific WebSocket session that owns the call_id.
    • fan_out: Sends incoming call notifications and IVR events to all WebSocket sessions subscribed to that specific context.
    • broadcast: Sends global events (such as agent state changes or DN registration) to all currently online WebSocket sessions.
    • webhook: Forwards events to a configured HTTP endpoint (can be filtered via an allow-list).
    | Method | Recipient | Meaning |
    |--------|-----------|--------|
    | `call_owner` | WS session owning the call_id | Per-call fine-grained events |
    | `fan_out` | All WS sessions subscribed to the context | Incoming call notifications, IVR events |
    | `broadcast` | All online WS sessions | Global events (agent state, DN registration, etc.) |
    | `webhook` | Configured HTTP endpoint | All events forwarded (filterable) |
  9. Understand the RWI Three-Layer Architecture

    main

    RustPBX uses a three-layer architecture to balance real-time performance with complex business logic:

    1. Layer 1: Realtime Processing (SIP/RTP): Handles DTMF auto-forwarding and INFO/OPTIONS passthrough. It operates with <10ms latency and is always available.
    2. Layer 2: Local Rule Engine: Provides fallback rules when the RWI connection is lost and handles hotkey-triggered local actions.
    3. Layer 3: RWI Application: Where complex business logic and real-time AI decisions reside.

    This separation ensures that even if the RWI application (Layer 3) disconnects, the call remains active and can be managed by local rules (Layer 2) or basic realtime processing (Layer 1).

  10. Use Flat Call Context (EventCallContext) in Events

    main

    Most call-scoped events in RustPBX include a set of standard metadata fields known as the Flat Call Context. These fields are embedded directly into the event JSON (using #[serde(flatten)]) rather than being nested in a sub-object. If a field is None, it is omitted from the JSON.

    Available Context Fields:

    • caller: Caller SIP URI
    • callee: Callee SIP URI
    • caller_name: Calling party number (normalized digits)
    • callee_name: Dialed number / DNIS
    • direction: inbound | outbound | internal
    • trunk: SIP trunk name
    • app_id: IVR application ID
    • routing_target: Current routing target
    • agent_id: Agent ID
    • agent_name: Agent display name

    Important Distinctions:

    • ani vs caller: ani is a plain number for business logic; caller is the full SIP URI.
    • dnis vs callee: dnis is the plain number; callee is the full SIP URI.
    • Automatic Enrichment: If an event (like RecordStopped) has its own specific field that is None, the system automatically backfills it from this context. Webhook consumers always receive the merged result.
  11. Compare SipFlow Storage Backends: SQLite vs FlowDB

    main

    SipFlow provides two local storage engines and one remote option. Use the following comparison to choose the right backend for your requirements:

    FeatureSQLite (legacy)FlowDB (default)
    Storage layoutsipflow.db (metadata) + data.raw (payloads)LSM-tree single directory
    Write methodBatch INSERT + transaction commitPer-record write_batch_sync
    CompressionPer-packet zstd (level 3, ≥96 bytes)Block-level LSM compression
    TTLNo auto-expiryBuilt-in TTL garbage collection
    Data isolationJOIN via call_meta tableKey prefix scan (sip:{id}:, rtp:{id}:)

    Recommendation: FlowDB is the default and significantly outperforms SQLite in write throughput (approx. 13x faster), disk efficiency (approx. 5.6x smaller), and query latency.

  12. Use TOML for translation files

    main

    RustPBX uses TOML for translation files (locales/*.toml) because it offers several advantages over JSON for localization tasks:

    • Readability: High (similar to INI format).
    • Comments: Supports # comments, allowing developers to leave notes for translators.
    • Multi-line Strings: Supports """ syntax, which is much cleaner than escaping \n in JSON.
    • Editing: More user-friendly and less prone to syntax errors like missing commas.