Skip to main content

ap_proxy_client/
config.rs

1use ap_proxy_protocol::{Identity, IdentityFingerprint, IdentityKeyPair, RendevouzCode};
2
3/// Configuration for creating a proxy client.
4///
5/// # Examples
6///
7/// Create a client with a new identity:
8///
9/// ```
10/// use ap_proxy_client::ProxyClientConfig;
11///
12/// let config = ProxyClientConfig {
13///     proxy_url: "ws://localhost:8080".to_string(),
14///     identity_keypair: None, // Will generate a new identity
15/// };
16/// ```
17///
18/// Create a client with an existing identity:
19///
20/// ```
21/// use ap_proxy_client::{ProxyClientConfig, IdentityKeyPair};
22///
23/// let keypair = IdentityKeyPair::generate();
24/// let config = ProxyClientConfig {
25///     proxy_url: "ws://localhost:8080".to_string(),
26///     identity_keypair: Some(keypair),
27/// };
28/// ```
29pub struct ProxyClientConfig {
30    /// WebSocket URL of the proxy server.
31    ///
32    /// Format: `ws://host:port` or `wss://host:port` for TLS.
33    ///
34    /// # Examples
35    /// - `"ws://localhost:8080"` - Local development
36    /// - `"wss://proxy.example.com:443"` - Production with TLS
37    pub proxy_url: String,
38
39    /// Optional identity keypair.
40    ///
41    /// If `None`, a new random identity will be generated on each connection.
42    /// If `Some`, the provided identity will be used for authentication.
43    ///
44    /// Use [`IdentityKeyPair::generate()`] to create a new identity, or
45    /// [`IdentityKeyPair::from_seed()`] to restore a previously saved identity.
46    pub identity_keypair: Option<IdentityKeyPair>,
47}
48
49/// Messages received by the client from the proxy server.
50///
51/// These messages are delivered via the channel returned by
52/// [`ProxyProtocolClient::connect()`](crate::ProxyProtocolClient::connect).
53///
54/// # Examples
55///
56/// ```no_run
57/// use ap_proxy_client::{ProxyClientConfig, ProxyProtocolClient, IncomingMessage};
58///
59/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
60/// let config = ProxyClientConfig {
61///     proxy_url: "ws://localhost:8080".to_string(),
62///     identity_keypair: None,
63/// };
64/// let mut client = ProxyProtocolClient::new(config);
65/// let mut incoming = client.connect().await?;
66///
67/// while let Some(msg) = incoming.recv().await {
68///     match msg {
69///         IncomingMessage::Send { source, payload, .. } => {
70///             println!("Message from {:?}: {} bytes", source, payload.len());
71///         }
72///         IncomingMessage::RendevouzInfo(code) => {
73///             println!("Your rendezvous code: {}", code.as_str());
74///         }
75///         IncomingMessage::IdentityInfo { identity, .. } => {
76///             println!("Found peer: {:?}", identity.fingerprint());
77///         }
78///     }
79/// }
80/// # Ok(())
81/// # }
82/// ```
83#[derive(Debug, Clone)]
84pub enum IncomingMessage {
85    /// Server responded with a rendezvous code.
86    ///
87    /// Received in response to [`ProxyProtocolClient::request_rendezvous()`](crate::ProxyProtocolClient::request_rendezvous).
88    /// The code can be shared with other clients to enable them to discover your identity.
89    ///
90    /// Codes expire after 5 minutes and are single-use.
91    RendevouzInfo(RendevouzCode),
92
93    /// Server responded with a peer's identity.
94    ///
95    /// Received in response to [`ProxyProtocolClient::request_identity()`](crate::ProxyProtocolClient::request_identity).
96    /// Contains the full identity and fingerprint of the peer who created the rendezvous code.
97    ///
98    /// After receiving this, you can send messages to the peer using their fingerprint.
99    IdentityInfo {
100        /// SHA256 fingerprint of the peer's identity
101        fingerprint: IdentityFingerprint,
102        /// The peer's full public identity
103        identity: Identity,
104    },
105
106    /// Received a message from another client.
107    ///
108    /// The `source` is cryptographically verified by the proxy server - it cannot be forged.
109    /// The `payload` should be decrypted or validated by the receiving client, as the proxy
110    /// does not inspect message contents.
111    Send {
112        /// The sender's fingerprint (validated by proxy)
113        source: IdentityFingerprint,
114        /// Your fingerprint (the recipient)
115        destination: IdentityFingerprint,
116        /// Arbitrary message payload (should be encrypted by clients)
117        payload: Vec<u8>,
118    },
119}
120
121/// Internal client connection state
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub(crate) enum ClientState {
124    Disconnected,
125    Connected,
126    Authenticated { fingerprint: IdentityFingerprint },
127}