openrtc 1.0.12

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
use anyhow::Result;
use async_trait::async_trait;
use futures::stream::BoxStream;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct RoomMemberSnapshot {
    #[serde(rename = "nodeId")]
    pub node_id: String,
    #[serde(rename = "userId")]
    pub user_id: String,
    pub ticket: String,
    #[serde(rename = "joinedAt")]
    pub joined_at: i64,
    #[serde(rename = "lastSeenAt")]
    pub last_seen_at: i64,
    #[serde(rename = "expiresAt", skip_serializing_if = "Option::is_none")]
    pub expires_at: Option<i64>,
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum RoomMemberEvent {
    Modified {
        member: RoomMemberSnapshot,
    },
    Removed {
        #[serde(rename = "memberId")]
        member_id: String,
    },
}

/// Provider-neutral room coordination boundary.
///
/// Managed products use the Cloudflare room avenue from the TypeScript SDK.
/// Standalone Rust hosts may inject another implementation. The default is
/// deliberately fail-closed and never derives a provider backend from a
/// project identifier.
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait RoomBackend: crate::signaling::SendSyncBound {
    async fn create_room(
        &self,
        room_id: &str,
        user_id: &str,
        ticket_str: &str,
        my_node_id: &str,
        app_tag: &str,
        max_members: Option<u32>,
    ) -> Result<bool>;

    async fn get_members(
        &self,
        room_id: &str,
        my_node_id: &str,
        app_tag: &str,
    ) -> Result<Vec<RoomMemberSnapshot>>;

    async fn join_room(
        &self,
        room_id: &str,
        user_id: &str,
        ticket_str: &str,
        my_node_id: &str,
        app_tag: &str,
    ) -> Result<()>;

    async fn leave_room(&self, room_id: &str, my_node_id: &str, app_tag: &str) -> Result<()>;

    async fn heartbeat_tick(&self, room_id: &str, member_id: &str, app_tag: &str) -> Result<()>;

    async fn subscribe_members(
        &self,
        room_id: &str,
        my_node_id: &str,
        app_tag: &str,
    ) -> Result<BoxStream<'static, Result<Vec<RoomMemberEvent>>>>;
}

#[derive(Debug, Default)]
pub struct GatewayRequiredRoomBackend;

impl GatewayRequiredRoomBackend {
    fn unavailable<T>() -> Result<T> {
        anyhow::bail!(
            "managed room coordination gateway is required; direct provider rooms have been removed"
        )
    }
}

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl RoomBackend for GatewayRequiredRoomBackend {
    async fn create_room(
        &self,
        _room_id: &str,
        _user_id: &str,
        _ticket_str: &str,
        _my_node_id: &str,
        _app_tag: &str,
        _max_members: Option<u32>,
    ) -> Result<bool> {
        Self::unavailable()
    }

    async fn get_members(
        &self,
        _room_id: &str,
        _my_node_id: &str,
        _app_tag: &str,
    ) -> Result<Vec<RoomMemberSnapshot>> {
        Self::unavailable()
    }

    async fn join_room(
        &self,
        _room_id: &str,
        _user_id: &str,
        _ticket_str: &str,
        _my_node_id: &str,
        _app_tag: &str,
    ) -> Result<()> {
        Self::unavailable()
    }

    async fn leave_room(&self, _room_id: &str, _my_node_id: &str, _app_tag: &str) -> Result<()> {
        Self::unavailable()
    }

    async fn heartbeat_tick(&self, _room_id: &str, _member_id: &str, _app_tag: &str) -> Result<()> {
        Self::unavailable()
    }

    async fn subscribe_members(
        &self,
        _room_id: &str,
        _my_node_id: &str,
        _app_tag: &str,
    ) -> Result<BoxStream<'static, Result<Vec<RoomMemberEvent>>>> {
        Self::unavailable()
    }
}