use anyhow::Result;
use async_trait::async_trait;
use futures::stream::BoxStream;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeviceCapabilities {
pub can_host: bool,
pub can_sync: bool,
pub read_only: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Device {
pub app_tag: Option<String>,
pub device_id: String,
pub user_id: Option<String>,
pub device_name: String,
pub platform_type: Option<String>,
pub capabilities: Option<DeviceCapabilities>,
pub session_id: Option<String>,
pub node_id: Option<String>,
pub tag: Option<String>,
pub kind: Option<String>,
pub metadata: Option<String>,
pub online: bool,
pub ticket: Option<String>,
pub last_seen_at: Option<serde_json::Value>,
pub expires_at: Option<serde_json::Value>,
pub created_at: Option<serde_json::Value>,
pub updated_at: Option<serde_json::Value>,
#[serde(default)]
pub excluded_peers: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct E2eeInfo {
pub session_key_id: String,
pub cipher_text: String,
pub iv: String,
pub salt: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignalingSession {
pub connection_id: String,
pub initiator: String,
pub target: String,
pub initiator_device_id: String,
pub target_device_id: String,
pub connection_type: Option<String>,
pub offer: Option<serde_json::Value>,
pub offer_e2ee: Option<E2eeInfo>,
pub answer: Option<serde_json::Value>,
pub answer_e2ee: Option<E2eeInfo>,
#[serde(default)]
pub ice_candidates: Vec<serde_json::Value>,
pub initiator_node_id: Option<String>,
pub target_node_id: Option<String>,
pub initiator_endpoint_addr: Option<String>,
pub target_endpoint_addr: Option<String>,
pub intent: Option<String>,
pub app_tag: Option<String>,
pub created_at: Option<i64>,
pub expires_at: Option<i64>,
pub state: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum SessionEvent {
Added {
session: SignalingSession,
},
Modified {
session: SignalingSession,
},
Removed {
#[serde(rename = "sessionId")]
session_id: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum DeviceEvent {
Added {
device: Device,
},
Modified {
device: Device,
},
Removed {
#[serde(rename = "deviceId")]
device_id: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignalingEnvelope {
#[serde(skip_serializing_if = "Option::is_none")]
pub app_tag: Option<String>,
pub sender_id: String,
pub target_id: String,
pub payload: String,
pub state: Option<String>,
pub reply_payload: Option<String>,
pub timestamp: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub sender_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<i64>,
}
#[cfg(target_arch = "wasm32")]
pub trait SendSyncBound {}
#[cfg(target_arch = "wasm32")]
impl<T> SendSyncBound for T {}
#[cfg(not(target_arch = "wasm32"))]
pub trait SendSyncBound: Send + Sync {}
#[cfg(not(target_arch = "wasm32"))]
impl<T: Send + Sync> SendSyncBound for T {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait SignalingBackend: SendSyncBound {
async fn update_presence(
&self,
user_id: &str,
local_node_id: &str,
ticket_str: &str,
is_online: bool,
name: &str,
ttl_ms: u64,
metadata: Option<&str>,
) -> Result<()>;
async fn set_offline(&self, user_id: &str, local_node_id: &str) -> Result<()>;
async fn update_device(
&self,
user_id: &str,
device_id: &str,
device_name: Option<&str>,
capabilities: Option<DeviceCapabilities>,
metadata: Option<&str>,
) -> Result<()>;
async fn delete_device(&self, user_id: &str, device_id: &str) -> Result<()>;
async fn set_excluded_peers(
&self,
user_id: &str,
local_node_id: &str,
excluded_peers: &[String],
) -> Result<()>;
async fn search_devices(
&self,
user_id: &str,
exclude_node_id: Option<&str>,
) -> Result<Vec<Device>>;
async fn list_devices(
&self,
user_id: &str,
exclude_node_id: Option<&str>,
) -> Result<Vec<Device>>;
async fn send_message(
&self,
sender_id: &str,
target_id: &str,
payload: &str,
state: Option<&str>,
reply_payload: Option<&str>,
) -> Result<String>;
async fn subscribe_devices(
&self,
user_id: &str,
) -> Result<BoxStream<'static, Result<Vec<DeviceEvent>>>>;
async fn create_session(&self, session: SignalingSession) -> Result<()>;
async fn update_session(&self, session_id: &str, update_data: serde_json::Value) -> Result<()>;
async fn subscribe_sessions(
&self,
local_device_id: &str,
) -> Result<BoxStream<'static, Result<Vec<SessionEvent>>>>;
}