Skip to main content

ping_core/
transport.rs

1//! Transport trait — the SDK never opens a socket. Hosts implement this against their backend.
2
3use crate::{
4    conversation::ConversationId, device::DeviceId, identity::UserId, message::MessageEnvelope,
5    sync::SyncCursor, Result,
6};
7use std::fmt::Debug;
8use std::future::Future;
9use std::pin::Pin;
10use std::sync::Arc;
11
12// See `storage.rs` — same reason: `JsFuture` is `!Send` on wasm32. The native bound is kept so
13// UniFFI's tokio multi-thread runtime can schedule the future across worker threads.
14#[cfg(not(target_arch = "wasm32"))]
15pub type TransportFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T>> + Send + 'a>>;
16#[cfg(target_arch = "wasm32")]
17pub type TransportFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T>> + 'a>>;
18
19/// Server returns events strictly after the given cursor, sorted by (epoch ASC, server_seq ASC).
20/// May return at-most-`limit` envelopes; caller pages.
21pub trait Transport: Send + Sync + Debug {
22    /// Publish a single envelope. Servers may batch; callers should not depend on it.
23    fn send<'a>(&'a self, envelope: MessageEnvelope) -> TransportFuture<'a, ()>;
24
25    /// Pull events for one conversation since `cursor`. Empty list = caught up.
26    fn fetch_since<'a>(
27        &'a self,
28        conversation_id: ConversationId,
29        cursor: SyncCursor,
30        limit: u32,
31    ) -> TransportFuture<'a, Vec<MessageEnvelope>>;
32
33    /// Subscribe to live events. Returned subscription's drop cancels.
34    fn subscribe<'a>(
35        &'a self,
36        callback: Arc<dyn Fn(MessageEnvelope) + Send + Sync>,
37    ) -> TransportFuture<'a, TransportSubscription>;
38
39    /// Look up published KeyPackages for a user's currently-active devices.
40    fn discover_devices<'a>(
41        &'a self,
42        user_id: UserId,
43    ) -> TransportFuture<'a, Vec<DiscoveredDevice>>;
44}
45
46#[derive(Debug, Clone)]
47pub struct DiscoveredDevice {
48    pub device_id: DeviceId,
49    pub key_package: Vec<u8>, // serialized OpenMLS KeyPackage
50}
51
52/// Cancels its subscription on drop.
53pub struct TransportSubscription {
54    pub(crate) cancel: Box<dyn FnOnce() + Send>,
55}
56
57impl std::fmt::Debug for TransportSubscription {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        f.write_str("TransportSubscription")
60    }
61}
62
63impl TransportSubscription {
64    pub fn new(cancel: impl FnOnce() + Send + 'static) -> Self {
65        Self {
66            cancel: Box::new(cancel),
67        }
68    }
69}
70
71impl Drop for TransportSubscription {
72    fn drop(&mut self) {
73        // Replace with a no-op closure so we can take ownership and call once.
74        let cancel = std::mem::replace(&mut self.cancel, Box::new(|| ()));
75        cancel();
76    }
77}