pushwire-core 0.1.1

Shared types and codecs for push-wire multiplexed push protocol
Documentation
use dashmap::{DashMap, DashSet};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// RTC signaling messages carried on the `rtc` channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum RtcMessage {
    Offer {
        from: Uuid,
        to: Uuid,
        sdp: String,
        #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
        meta: serde_json::Value,
    },
    Answer {
        from: Uuid,
        to: Uuid,
        sdp: String,
        #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
        meta: serde_json::Value,
    },
    Candidate {
        from: Uuid,
        to: Uuid,
        candidate: String,
    },
    CandidateBatch {
        from: Uuid,
        to: Uuid,
        candidates: Vec<String>,
    },
    Status {
        from: Uuid,
        to: Uuid,
        status: String,
    },
    PeerList {
        peers: Vec<Uuid>,
    },
    PeerDiscovery {
        #[serde(default, skip_serializing_if = "Option::is_none")]
        room: Option<String>,
    },
    TurnCredentials(TurnCredential),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TurnCredential {
    pub username: String,
    pub credential: String,
    pub ttl_seconds: u64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub server: Option<String>,
}

#[derive(Debug, Default)]
pub struct RtcRouter {
    /// Per (from,to) deduplication set for candidates to avoid floods.
    seen_candidates: DashMap<(Uuid, Uuid), DashSet<String>>,
}

impl RtcRouter {
    pub fn new() -> Self {
        Self {
            seen_candidates: DashMap::new(),
        }
    }

    pub fn dedup_candidate(&self, from: Uuid, to: Uuid, candidate: &str) -> bool {
        let set = self.seen_candidates.entry((from, to)).or_default();
        set.insert(candidate.to_string())
    }

    pub fn dedup_batch(&self, from: Uuid, to: Uuid, candidates: Vec<String>) -> Vec<String> {
        candidates
            .into_iter()
            .filter(|c| self.dedup_candidate(from, to, c))
            .collect()
    }
}