1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use std::{collections::HashSet, path::PathBuf};

pub const NO_PREFERRED_ROUTE_HINT: u32 = 0;

/// A configuration object specifying which network transports Ditto should use
/// to sync data.
///
/// A `Ditto` object comes with a default transport configuration where all
/// available peer-to-peer transports are enabled. You can customize this by
/// initializing a `TransportConfig`, adjusting its properties, and supplying it
/// to `set_transport_config()` on `Ditto`.
///
/// When you initialize a `TransportConfig` yourself it starts with all
/// transports disabled. You must enable each one directly.
///
/// Peer-to-peer transports will automatically discover peers in the vicinity
/// and create connections without any configuration. These are configured
/// inside the `peer_to_peer` property. To turn each one on, set its `enabled`
/// property to `true`.
///
/// To connect to a peer at a known location, such as a Ditto Big Peer, add its
/// address inside the `connect` configuration. These are either `host:port`
/// strings for raw TCP sync, or a `wss://…` URL for websockets.
///
/// The `listen` configurations are for specific less common data sync
/// scenarios. Please read the documentation on the Ditto website for examples.
/// Incorrect use of `listen` can result in insecure configurations.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct TransportConfig {
    pub peer_to_peer: PeerToPeer,
    pub connect: Connect,
    pub listen: Listen,
    pub global: Global,
}

impl TransportConfig {
    pub fn new() -> Self {
        Self {
            peer_to_peer: PeerToPeer {
                bluetooth_le: BluetoothLEConfig::new(),
                lan: LanConfig::new(),
            },
            connect: Connect {
                tcp_servers: HashSet::new(),
                websocket_urls: HashSet::new(),
            },
            listen: Listen {
                tcp: TcpListenConfig::new(),
                http: HttpListenConfig::new(),
            },
            global: Global {
                sync_group: 0,
                routing_hint: NO_PREFERRED_ROUTE_HINT,
            },
        }
    }

    pub fn enable_all_peer_to_peer(&mut self) {
        self.peer_to_peer.bluetooth_le.enabled = true;
        self.peer_to_peer.lan.enabled = true;
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct PeerToPeer {
    pub bluetooth_le: BluetoothLEConfig,
    pub lan: LanConfig,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Connect {
    pub tcp_servers: HashSet<String>,
    pub websocket_urls: HashSet<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Listen {
    pub tcp: TcpListenConfig,
    pub http: HttpListenConfig,
}

/// Settings not associated with any specific type of transport.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Global {
    /// The sync group for this device.
    ///
    /// When peer-to-peer transports are enabled, all devices with the same App
    /// ID will normally form an interconnected mesh network. In some
    /// situations it may be  desirable to have distinct groups of devices
    /// within the same app, so that connections will only be formed within
    /// each group. The `sync_group` parameter changes that group
    /// membership. A device can only ever be in one sync group, which
    /// by default is group 0. Up to 2^32 distinct group numbers can be used in
    /// an app.
    ///
    /// This is an optimization, not a security control. If a connection is
    /// created manually, such as by specifying a `connect` transport, then
    /// devices from different sync groups will still sync as normal. If
    /// two groups of devices are intended to have access to different data
    /// sets, this must be enforced using  Ditto's permissions system.
    pub sync_group: u32,

    /// The routing hint for this device.
    ///
    /// A routing hint is a performance tuning option which can improve the performance of
    /// applications that use large collections. Ditto will make a best effort to co-locate data
    /// for the same routing key. In most circumstances, this should substantially improve
    /// responsiveness of the Ditto Cloud.
    ///
    /// The value of the routing hint is application specific - you are free to chose any value.
    /// Devices which you expect to operate on much the same data should be configured to
    /// use the same value.
    ///
    /// A routing hint does not partition data. The value of the routing hint will not affect the
    /// data returned for a query. The routing hint only improves the efficiency of the Cloud's
    /// ability to satisfy the query.
    pub routing_hint: u32,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct HttpListenConfig {
    pub enabled: bool,
    pub interface_ip: String,
    pub port: u16,
    pub static_content_path: Option<PathBuf>,
    pub websocket_sync: bool,
    pub tls_key_path: Option<PathBuf>,
    pub tls_certificate_path: Option<PathBuf>,
}

impl HttpListenConfig {
    pub fn new() -> Self {
        Self {
            enabled: false,
            interface_ip: "[::]".to_string(),
            port: 80,
            static_content_path: None,
            websocket_sync: true,
            tls_key_path: None,
            tls_certificate_path: None,
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct TcpListenConfig {
    pub enabled: bool,
    pub interface_ip: String,
    pub port: u16,
}

impl TcpListenConfig {
    pub fn new() -> Self {
        Self {
            enabled: false,
            interface_ip: "[::]".to_string(),
            port: 4040,
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct BluetoothLEConfig {
    pub enabled: bool,
}

impl BluetoothLEConfig {
    pub fn new() -> Self {
        Self { enabled: false }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct LanConfig {
    pub enabled: bool,
    pub mdns_enabled: bool,
    pub multicast_enabled: bool,
}

impl LanConfig {
    pub fn new() -> Self {
        Self {
            enabled: false,
            mdns_enabled: true,
            multicast_enabled: true,
        }
    }
}