dittolive_ditto/transport/
transport_config.rs

1use std::{collections::HashSet, path::PathBuf, time::Duration};
2
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5
6pub const NO_PREFERRED_ROUTE_HINT: u32 = 0;
7
8/// A configuration object specifying which network transports Ditto should use
9/// to sync data.
10///
11/// A `Ditto` object comes with a default transport configuration where all
12/// available peer-to-peer transports are enabled. You can customize this by
13/// initializing a `TransportConfig`, adjusting its properties, and supplying it
14/// to `set_transport_config()` on `Ditto`.
15///
16/// When you initialize a `TransportConfig` yourself it starts with all
17/// transports disabled. You must enable each one directly.
18///
19/// Peer-to-peer transports will automatically discover peers in the vicinity
20/// and create connections without any configuration. These are configured
21/// inside the `peer_to_peer` property. To turn each one on, set its `enabled`
22/// property to `true`.
23///
24/// To connect to a peer at a known location, such as a Ditto Big Peer, add its
25/// address inside the `connect` configuration. These are either `host:port`
26/// strings for raw TCP sync, or a `wss://…` URL for websockets.
27///
28/// The `listen` configurations are for specific less common data sync
29/// scenarios. Please read the documentation on the Ditto website for examples.
30/// Incorrect use of `listen` can result in insecure configurations.
31#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
32pub struct TransportConfig {
33    /// Configure Bluetooth and LAN transports.
34    pub peer_to_peer: PeerToPeer,
35
36    /// Configure TCP and WebSocket outbound transports.
37    pub connect: Connect,
38
39    /// Configure TCP and HTTP inbound transports.
40    pub listen: Listen,
41
42    /// Set peer-global transport settings.
43    pub global: Global,
44}
45
46impl TransportConfig {
47    /// Create a new [`TransportConfig`] with default settings.
48    pub fn new() -> Self {
49        Self {
50            peer_to_peer: PeerToPeer {
51                bluetooth_le: BluetoothLEConfig::new(),
52                lan: LanConfig::new(),
53            },
54            connect: Connect {
55                tcp_servers: HashSet::new(),
56                websocket_urls: HashSet::new(),
57                retry_interval: Duration::from_secs(5),
58            },
59            listen: Listen {
60                tcp: TcpListenConfig::new(),
61                http: HttpListenConfig::new(),
62            },
63            global: Global {
64                sync_group: 0,
65                routing_hint: NO_PREFERRED_ROUTE_HINT,
66            },
67        }
68    }
69
70    /// Enables peer-to-peer transports in this config.
71    pub fn enable_all_peer_to_peer(&mut self) {
72        self.peer_to_peer.bluetooth_le.enabled = true;
73        self.peer_to_peer.lan.enabled = true;
74    }
75}
76
77/// Configure peer-to-peer transports such as Bluetooth and LAN.
78#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
79pub struct PeerToPeer {
80    /// Bluetooth transport configurations.
81    pub bluetooth_le: BluetoothLEConfig,
82
83    /// LAN transport configurations.
84    pub lan: LanConfig,
85}
86
87/// Configure outbound transports such as TCP and WebSocket dialing.
88#[serde_as]
89#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
90pub struct Connect {
91    /// A set of TCP servers to attempt connection to.
92    pub tcp_servers: HashSet<String>,
93
94    /// A set of websocket servers to attempt connection to.
95    pub websocket_urls: HashSet<String>,
96
97    /// The retry interval between failed connection attempts. For
98    /// cross-compatibility, this must be less than 2^32 - 1 milliseconds.
99    #[serde_as(as = "::serde_with::DurationMilliSeconds<u64>")]
100    pub retry_interval: Duration,
101}
102
103/// Configure inbound transports such as TCP and HTTP servers.
104#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
105pub struct Listen {
106    /// Configure inbound TCP transports.
107    pub tcp: TcpListenConfig,
108
109    /// Configure inbound HTTP transports.
110    pub http: HttpListenConfig,
111}
112
113/// Settings not associated with any specific type of transport.
114#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
115pub struct Global {
116    /// The sync group for this device.
117    ///
118    /// When peer-to-peer transports are enabled, all devices with the same App
119    /// ID will normally form an interconnected mesh network. In some
120    /// situations it may be  desirable to have distinct groups of devices
121    /// within the same app, so that connections will only be formed within
122    /// each group. The `sync_group` parameter changes that group
123    /// membership. A device can only ever be in one sync group, which
124    /// by default is group 0. Up to 2^32 distinct group numbers can be used in
125    /// an app.
126    ///
127    /// This is an optimization, not a security control. If a connection is
128    /// created manually, such as by specifying a `connect` transport, then
129    /// devices from different sync groups will still sync as normal. If
130    /// two groups of devices are intended to have access to different data
131    /// sets, this must be enforced using  Ditto's permissions system.
132    pub sync_group: u32,
133
134    /// The routing hint for this device.
135    ///
136    /// A routing hint is a performance tuning option which can improve the performance of
137    /// applications that use large collections. Ditto will make a best effort to co-locate data
138    /// for the same routing key. In most circumstances, this should substantially improve
139    /// responsiveness of the Ditto Cloud.
140    ///
141    /// The value of the routing hint is application specific - you are free to chose any value.
142    /// Devices which you expect to operate on much the same data should be configured to
143    /// use the same value.
144    ///
145    /// A routing hint does not partition data. The value of the routing hint will not affect the
146    /// data returned for a query. The routing hint only improves the efficiency of the Cloud's
147    /// ability to satisfy the query.
148    pub routing_hint: u32,
149}
150
151/// Configure inbound HTTP transports.
152#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
153pub struct HttpListenConfig {
154    /// Whether inbound HTTP is enabled.
155    pub enabled: bool,
156
157    /// The IP address on which to bind a listenting HTTP server.
158    pub interface_ip: String,
159
160    /// The port on which to bind a listening HTTP server.
161    pub port: u16,
162
163    /// An optional path to static files to make available to clients.
164    pub static_content_path: Option<PathBuf>,
165
166    /// Whether to enable Websocket sync on this transport.
167    pub websocket_sync: bool,
168
169    /// Optional path to a TLS key file.
170    pub tls_key_path: Option<PathBuf>,
171
172    /// Optional path to a TLS certificate file.
173    pub tls_certificate_path: Option<PathBuf>,
174}
175
176impl HttpListenConfig {
177    /// Create a new [`HttpListenConfig`] with default settings.
178    pub fn new() -> Self {
179        Self {
180            enabled: false,
181            interface_ip: "[::]".to_string(),
182            port: 80,
183            static_content_path: None,
184            websocket_sync: true,
185            tls_key_path: None,
186            tls_certificate_path: None,
187        }
188    }
189}
190
191/// Configure inbound TCP transports.
192#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
193pub struct TcpListenConfig {
194    /// Whether inbound TCP is enabled.
195    pub enabled: bool,
196
197    /// The address to bind a TCP listener, such as `0.0.0.0`.
198    pub interface_ip: String,
199
200    /// The port to bind the TCP listener to.
201    pub port: u16,
202}
203
204impl TcpListenConfig {
205    /// Create a new [`TcpListenConfig`] with default settings.
206    pub fn new() -> Self {
207        Self {
208            enabled: false,
209            interface_ip: "[::]".to_string(),
210            port: 4040,
211        }
212    }
213}
214
215/// Configure the Bluetooth Low-Energy transport.
216#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
217pub struct BluetoothLEConfig {
218    /// Whether to enable the Bluetooth Low-Energy transport.
219    pub enabled: bool,
220}
221
222impl BluetoothLEConfig {
223    /// Create a new [`BluetoothLEConfig`] with default settings.
224    pub fn new() -> Self {
225        Self { enabled: false }
226    }
227}
228
229/// Configure the Local Area Network (LAN) transport.
230#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
231pub struct LanConfig {
232    /// Whether to enable the LAN transport.
233    pub enabled: bool,
234
235    /// Whether to enable mDNS peer discovery.
236    pub mdns_enabled: bool,
237
238    /// Whether to enable multicast.
239    pub multicast_enabled: bool,
240}
241
242impl LanConfig {
243    /// Create a new [`LanConfig`] with default settings.
244    pub fn new() -> Self {
245        Self {
246            enabled: false,
247            mdns_enabled: true,
248            multicast_enabled: true,
249        }
250    }
251}