Matrix Rust SDK

repository·main·Indexed 24 days ago

https://github.com/matrix-org/matrix-rust-sdk

A collection of libraries for creating Matrix clients in Rust, from bots to full-featured applications. The SDK handles low-level tasks including end-to-end encryption, room state management, and synchronization. It provides high-level crates like matrix-sdk and specialized crates such as matrix-sdk-crypto for E2EE state machine management, along with official FFI bindings for Swift, Kotlin, Python, and Ruby.

Tokens
60.6K
Snippets
78
Records
338
Agent score
80%

What's inside matrix-rust-sdk

  1. Use the Widget Driver to bridge Matrix and Webviews

    main

    The WidgetDriver in the Rust SDK implements the logic required to allow a client to provide widgets (webviews) access to Matrix via the postMessage API.

    It supports several features defined in Matrix specifications:

    • MSC3803: Matrix Widget API v2
    • MSC2762: Sending/receiving events
    • MSC4157: Delayed Events
    • MSC3819: Sending/receiving to-device messages

    Key Capabilities:

    • Sending and reading Matrix events.
    • Rudimentary client navigation.
    • Retrieving an OpenID token (for user identification).
    • Querying supported API versions.
    • Notifying the client when a widget has loaded and is ready.
  2. Use the matrix-sdk crate for client operations

    main

    The matrix-sdk crate is the main entry point for most developers. It provides two primary abstractions:

    • Client: Used for room-independent operations such as logging in/out, creating rooms, and running the sync process.
    • Room: Represents a specific room and its state (accessible via the observable RoomInfo). It is used for room-specific queries and sending events.
  3. Available Matrix Rust SDK bindings

    main

    The Matrix Rust SDK provides several official bindings for different programming languages and platforms. These bindings allow you to use the core Rust logic in non-Rust environments.

    Official Bindings (Maintained in this repository)

    • Swift: Available via the apple or matrix-rust-components-swift packages. These provide Swift bindings for the matrix-sdk crate using matrix-sdk-ffi.
    • Multi-language (Kotlin, Swift, Python, Ruby): The matrix-sdk-crypto-ffi package provides UniFFI-based bindings specifically for the matrix-sdk-crypto crate.
    • General FFI: The matrix-sdk-ffi package provides UniFFI bindings for the high-level matrix-sdk crate.

    External Bindings

    • JavaScript / WebAssembly: The matrix-sdk-crypto-wasm repository provides WASM bindings for the matrix-sdk-crypto crate.
    • Node.js: The matrix-sdk-crypto-nodejs repository provides Node.js bindings for the matrix-sdk-crypto crate.
  4. Choose the right Matrix Rust SDK crate for your project

    main

    The Matrix Rust SDK is composed of several crates designed for different use cases. Depending on whether you are building a full UI, a bot, or a custom encryption layer, you should choose the appropriate crate:

    • matrix-sdk-ui: Use this for building full-featured UI clients with minimal setup. It is a high-level library. For a reference implementation, see the multiverse project.
    • matrix-sdk: Use this for building bots, custom clients, or higher-level abstractions. It is a mid-level library that handles low-level details like encryption, syncing, and room state.
    • matrix-sdk-crypto: Use this if you need a standalone encryption state machine with no network I/O. It provides end-to-end encryption support.

    Note: Other crates in the repository are considered internal-only and should not be used as direct dependencies.

  5. Understanding the modular architecture of matrix-rust-sdk

    main

    The matrix-rust-sdk is designed modularly. While matrix-sdk is the high-level, batteries-included client, you may want to use lower-level crates for custom implementations:

    • matrix_sdk_base: A no-network-IO client state machine. Use this to embed a Matrix client into an existing network stack or to build a new client library.
    • matrix_sdk_crypto: A no-network-IO encryption state machine. Use this to add Matrix E2EE support to an existing client or library.
  6. How to perform quick refreshing in Sliding Sync

    main

    Because Sliding Sync is long-polling, a client might be stuck waiting for stream.next().await when a new request (like a list range update) is needed.

    To achieve a 'snappy' UI, you can spawn a new Future that calls SlidingSync::sync(). This new request will cause the previous long-polling connection to return immediately.

    Important considerations:

    • The spawned Future can be cancelled safely.
    • If a response was just being received when cancelled, SlidingSync handles it in a "detached mode" to ensure the data is processed.
    • SlidingSync cannot handle responses concurrently; it processes them sequentially.
  7. How to use the Widget API

    main

    To implement a widget in a Matrix client using the matrix-sdk, you must coordinate two main components: a CapabilitiesProvider and a WidgetDriver.

    1. CapabilitiesProvider: An implementation of this trait that handles permission requests. When a widget requests specific permissions (e.g., reading m.room.message events), the acquire_capabilities method is called. You should use this to prompt the user and return the subset of capabilities they have approved.

    2. WidgetDriver: This manages the communication lifecycle. It consists of two parts:

      • driver: Use the run method to start the widget communication within a specific room.
      • handle: A communication handle used to bridge the gap between the SDK and your platform's message system (e.g., a web browser's postMessage).
        • Use handle.send(message) to pass JSON messages received from the widget to the SDK.
        • Use handle.recv() to receive JSON messages emitted by the SDK that need to be sent to the widget.
  8. Understand Sliding Sync List modes

    main

    Sliding Sync lists operate in different modes to balance bandwidth and completeness:

    • SlidingSyncMode::Selective (Default): The client explicitly requests specific ranges of room indexes (e.g., the top 10 most recent rooms).
    • SlidingSyncMode::Paging: The client pages through the entire room list one batch at a time, requesting the next batch_size of rooms until the end or until maximum_number_of_rooms_to_fetch is reached.
    • SlidingSyncMode::Growing: The client window grows by batch_size on every request until all rooms or the maximum_number_of_rooms_to_fetch limit is reached.
  9. How the matrix-sdk-crypto state machine works

    main

    The matrix-sdk-crypto crate provides a no-network-IO implementation of a state machine designed to handle end-to-end encryption (E2EE) for Matrix clients.

    It operates using a push/pull model:

    1. Push: You push state changes and events (retrieved from a Matrix homeserver via /sync responses) into the state machine.
    2. Pull: You pull requests from the state machine that need to be sent back to the homeserver to maintain encryption state.

    Note: If you are building a standard Matrix client or bot in Rust, you should use the high-level matrix-sdk crate instead. Use matrix-sdk-crypto only if you are adding E2EE support to an existing client or library.

    use std::collections::BTreeMap;
    
    use matrix_sdk_crypto::{
        DecryptionSettings, EncryptionSyncChanges, OlmError, OlmMachine, TrustRequirement,
    };
    use ruma::{api::client::sync::sync_events::DeviceLists, device_id, user_id};
    
    #[tokio::main]
    async fn main() -> Result<(), OlmError> {
        let alice = user_id!("@alice:example.org");
        let machine = OlmMachine::new(&alice, device_id!("DEVICEID")).await;
    
        let changed_devices = DeviceLists::default();
        let one_time_key_counts = BTreeMap::default();
        let unused_fallback_keys = Some(Vec::new());
        let next_batch_token = "T0K3N".to_owned();
    
        let decryption_settings = 
            DecryptionSettings { sender_device_trust_requirement: TrustRequirement::Untrusted };
    
        // Push changes that the server sent to us in a sync response.
        let decrypted_to_device = machine
            .receive_sync_changes(
                EncryptionSyncChanges {
                    to_device_events: vec![],
                    changed_devices: &changed_devices,
                    one_time_keys_counts: &one_time_key_counts,
                    unused_fallback_keys: unused_fallback_keys.as_deref(),
                    next_batch_token: Some(next_batch_token),
                },
                &decryption_settings,
            )
            .await?;
    
        // Pull requests that we need to send out.
        let outgoing_requests = machine.outgoing_requests().await?;
    
        // Send the requests out here and call machine.mark_request_as_sent().
    
        Ok()
    }
  10. Understand the Matrix Rust SDK architecture

    main

    The SDK is organized into several layers, ranging from low-level storage and crypto logic to high-level UI services and cross-language bindings.

    Core Layers

    • Main Client (matrix-sdk): The primary entry point for most consumers.
    • Base Logic (matrix-sdk-base): Defines core data types and storage traits (StateStore, EventCacheStore) without performing I/O.
    • Crypto (matrix-sdk-crypto): A state machine for end-to-end encryption (E2EE) that is sans I/O, relying on a CryptoStore trait for persistence.
    • Common (matrix-sdk-common): Shared helpers used across the dependency tree.

    Storage Implementations

    Storage backends implement the traits defined in the base/crypto crates:

    • matrix-sdk-sqlite: For SQLite-based persistence.
    • matrix-sdk-indexeddb: For WebAssembly/Browser environments using IndexedDB.
    • MemoryStore: A dummy in-memory implementation defined in matrix-sdk-base.

    High-Level UI Services (matrix-sdk-ui)

    Provides specialized services for advanced Matrix features:

    • EncryptionSyncService: Handles E2EE and crypto-related tasks using simplified sliding sync (MSC4186).
    • RoomListService: Manages the list of current rooms via simplified sliding sync.
    • SyncService: A coordinator that manages the lifecycle (start/shutdown) of both the EncryptionSyncService and RoomListService.
    • Timeline: A high-level view of a Room's events, aggregating related events into single items.