ap_proxy_client/config.rs
1use ap_proxy_protocol::{Identity, IdentityFingerprint, IdentityKeyPair, RendezvousCode};
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::RendezvousInfo(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 RendezvousInfo(RendezvousCode),
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}