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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
use crate::{
    data_types::*,
    error::{ErrorKind, Lib3hProtocolError},
    protocol_client::Lib3hClientProtocol,
    protocol_server::Lib3hServerProtocol,
    types::NetworkHash,
    uri::Lib3hUri,
};

use std::convert::TryFrom;
/// Enum holding the message types describe the lib3h protocol.
/// There are 4 categories of messages:
///  - ClientToLib3h: A request or event sent from the user/client of lib3h
/// (i.e. the Holochain node) to lib3h.
///  - ClientToLib3hResponse: A response to a ClientToLib3h. The name always matches what it's a response to. The response may have no data associated with it, in which case its use is in the Err
///  - Lib3hToClient: A request or event sent from lib3h its user/client.
///  - Lib3hToClientResponse: A response from the client back to lib3h.
/// Fetch = Request between node and the network (other nodes)
/// Get   = Request within a node between p2p module and core

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ClientToLib3h {
    // -- Connection -- //
    /// create an explicit connection to a remote peer
    Bootstrap(BootstrapData),

    // -- Space -- //
    /// Order the engine to be part of the network of the specified space.
    JoinSpace(SpaceData),
    /// Order the engine to leave the network of the specified space.
    LeaveSpace(SpaceData),

    // -- Direct Messaging -- //
    /// Send a message directly to another agent on the network
    SendDirectMessage(DirectMessageData),

    // -- Entry -- //
    /// Request an Entry from the dht network
    FetchEntry(FetchEntryData), // NOTE: MAY BE DEPRECATED
    /// Publish data to the dht (event)
    PublishEntry(ProvidedEntryData),
    /// Request some info / data from a Entry
    QueryEntry(QueryEntryData),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ClientToLib3hResponse {
    /// we were able to bootstrap to the remote
    BootstrapSuccess,

    /// the response received from a previous `SendDirectMessage`
    SendDirectMessageResult(DirectMessageData),

    /// Response from requesting dht data from the network
    FetchEntryResult(FetchEntryResultData),
    /// Response to a `QueryEntry` request
    QueryEntryResult(QueryEntryResultData),

    JoinSpaceResult,  // response to the ClientToLib3h::JoinSpace() request, Ok or Err
    LeaveSpaceResult, // response to the ClientToLib3h::LeaveSpace() request, Ok or Err
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Lib3hToClient {
    // -- Connection -- //
    /// Notification of successful connection to a network
    Connected(ConnectedData),
    /// Notification of disconnection from a network
    Unbound(UnboundData),

    // -- Direct Messaging -- //
    /// the response received from a previous `SendDirectMessage`
    SendDirectMessageResult(DirectMessageData),
    /// Request to handle a direct message another agent has sent us.
    HandleSendDirectMessage(DirectMessageData),

    // -- Entry -- //
    /// Another node, or the network module itself is requesting data from us
    HandleFetchEntry(FetchEntryData),
    /// Store data on a node's dht arc.
    HandleStoreEntryAspect(StoreEntryAspectData),
    /// Local client does not need to hold that entry anymore.
    /// Local client doesn't 'have to' comply.
    HandleDropEntry(DropEntryData),
    /// Request a node to handle a QueryEntry request
    HandleQueryEntry(QueryEntryData),

    // -- Entry lists -- //
    HandleGetAuthoringEntryList(GetListData),
    HandleGetGossipingEntryList(GetListData),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Lib3hToClientResponse {
    /// Our response to a direct message from another agent.
    HandleSendDirectMessageResult(DirectMessageData),
    /// Successful data response for a `HandleFetchEntryData` request
    HandleFetchEntryResult(FetchEntryResultData),
    HandleStoreEntryAspectResult,
    HandleDropEntryResult,
    /// Response to a `HandleQueryEntry` request
    HandleQueryEntryResult(QueryEntryResultData),
    // -- Entry lists -- //
    HandleGetAuthoringEntryListResult(EntryListData),
    HandleGetGossipingEntryListResult(EntryListData),
}

impl TryFrom<Lib3hClientProtocol> for ClientToLib3h {
    type Error = Lib3hProtocolError;
    fn try_from(c: Lib3hClientProtocol) -> Result<Self, Self::Error> {
        match c {
            Lib3hClientProtocol::Connect(connect_data) => {
                Ok(ClientToLib3h::Bootstrap(BootstrapData {
                    network_or_space_address: connect_data.network_id.clone().into(),
                    bootstrap_uri: connect_data.peer_location,
                }))
            }
            Lib3hClientProtocol::JoinSpace(space_data) => Ok(ClientToLib3h::JoinSpace(space_data)),
            Lib3hClientProtocol::LeaveSpace(space_data) => {
                Ok(ClientToLib3h::LeaveSpace(space_data))
            }
            Lib3hClientProtocol::SendDirectMessage(direct_message_data) => {
                Ok(ClientToLib3h::SendDirectMessage(direct_message_data))
            }
            Lib3hClientProtocol::FetchEntry(fetch_entry_data) => {
                Ok(ClientToLib3h::FetchEntry(fetch_entry_data))
            }
            Lib3hClientProtocol::PublishEntry(provided_entry_data) => {
                Ok(ClientToLib3h::PublishEntry(provided_entry_data))
            }
            Lib3hClientProtocol::QueryEntry(query_entry_data) => {
                Ok(ClientToLib3h::QueryEntry(query_entry_data))
            }
            variant => Err(Lib3hProtocolError::new(ErrorKind::Other(format!(
                "{:?} can't convert to ClientToLib3h",
                variant
            )))),
        }
    }
}

impl TryFrom<Lib3hClientProtocol> for Lib3hToClientResponse {
    type Error = Lib3hProtocolError;
    fn try_from(c: Lib3hClientProtocol) -> Result<Self, Self::Error> {
        match c {
            Lib3hClientProtocol::HandleSendDirectMessageResult(direct_message_data) => Ok(
                Lib3hToClientResponse::HandleSendDirectMessageResult(direct_message_data),
            ),
            Lib3hClientProtocol::HandleFetchEntryResult(fetch_entry_result_data) => Ok(
                Lib3hToClientResponse::HandleFetchEntryResult(fetch_entry_result_data),
            ),
            Lib3hClientProtocol::HandleQueryEntryResult(query_entry_result_data) => Ok(
                Lib3hToClientResponse::HandleQueryEntryResult(query_entry_result_data),
            ),
            Lib3hClientProtocol::HandleGetAuthoringEntryListResult(entry_list_data) => Ok(
                Lib3hToClientResponse::HandleGetAuthoringEntryListResult(entry_list_data),
            ),
            Lib3hClientProtocol::HandleGetGossipingEntryListResult(entry_list_data) => Ok(
                Lib3hToClientResponse::HandleGetGossipingEntryListResult(entry_list_data),
            ),
            variant => Err(Lib3hProtocolError::new(ErrorKind::Other(format!(
                "{:?} can't convert to Lib3hToClientResponse",
                variant
            )))),
        }
    }
}

impl TryFrom<Lib3hServerProtocol> for Lib3hToClient {
    type Error = Lib3hProtocolError;
    fn try_from(c: Lib3hServerProtocol) -> Result<Self, Self::Error> {
        match c {
            Lib3hServerProtocol::Connected(connected_data) => {
                Ok(Lib3hToClient::Connected(connected_data))
            }
            Lib3hServerProtocol::Disconnected(_disconnected_data) => {
                Ok(Lib3hToClient::Unbound(UnboundData {
                    uri: Lib3hUri::with_undefined(),
                }))
            }
            Lib3hServerProtocol::SendDirectMessageResult(direct_message_data) => {
                Ok(Lib3hToClient::SendDirectMessageResult(direct_message_data))
            }
            Lib3hServerProtocol::HandleSendDirectMessage(direct_message_data) => {
                Ok(Lib3hToClient::HandleSendDirectMessage(direct_message_data))
            }
            Lib3hServerProtocol::HandleFetchEntry(fetch_entry_data) => {
                Ok(Lib3hToClient::HandleFetchEntry(fetch_entry_data))
            }
            Lib3hServerProtocol::HandleStoreEntryAspect(store_entry_aspect_data) => Ok(
                Lib3hToClient::HandleStoreEntryAspect(store_entry_aspect_data),
            ),
            Lib3hServerProtocol::HandleDropEntry(drop_entry_data) => {
                Ok(Lib3hToClient::HandleDropEntry(drop_entry_data))
            }
            Lib3hServerProtocol::HandleQueryEntry(query_entry_data) => {
                Ok(Lib3hToClient::HandleQueryEntry(query_entry_data))
            }
            Lib3hServerProtocol::HandleGetAuthoringEntryList(get_list_data) => {
                Ok(Lib3hToClient::HandleGetAuthoringEntryList(get_list_data))
            }
            Lib3hServerProtocol::HandleGetGossipingEntryList(get_list_data) => {
                Ok(Lib3hToClient::HandleGetGossipingEntryList(get_list_data))
            }
            variant => Err(Lib3hProtocolError::new(ErrorKind::Other(format!(
                "{:?} can't convert to Lib3hToClient",
                variant
            )))),
        }
    }
}

impl From<Lib3hServerProtocol> for ClientToLib3hResponse {
    fn from(c: Lib3hServerProtocol) -> Self {
        match c {
            Lib3hServerProtocol::SendDirectMessageResult(direct_message_data) => {
                ClientToLib3hResponse::SendDirectMessageResult(direct_message_data)
            }
            Lib3hServerProtocol::FetchEntryResult(fetch_entry_result_data) => {
                ClientToLib3hResponse::FetchEntryResult(fetch_entry_result_data)
            }

            Lib3hServerProtocol::QueryEntryResult(query_entry_result_data) => {
                ClientToLib3hResponse::QueryEntryResult(query_entry_result_data)
            }
            Lib3hServerProtocol::Connected(_connected_data) => {
                ClientToLib3hResponse::BootstrapSuccess
            }
            variant => panic!("{:?} can't convert to ClientToLib3hResponse", variant),
        }
    }
}
///////////////////////////////////////////
impl From<ClientToLib3h> for Lib3hClientProtocol {
    fn from(c: ClientToLib3h) -> Self {
        match c {
            ClientToLib3h::Bootstrap(bootstrap_data) => Lib3hClientProtocol::Connect(ConnectData {
                request_id: "".to_string(),
                peer_location: bootstrap_data.bootstrap_uri,
                network_id: bootstrap_data.network_or_space_address.into(),
            }),
            ClientToLib3h::JoinSpace(space_data) => Lib3hClientProtocol::JoinSpace(space_data),
            ClientToLib3h::LeaveSpace(space_data) => Lib3hClientProtocol::LeaveSpace(space_data),
            ClientToLib3h::SendDirectMessage(direct_message_data) => {
                Lib3hClientProtocol::SendDirectMessage(direct_message_data)
            }
            ClientToLib3h::FetchEntry(fetch_entry_data) => {
                Lib3hClientProtocol::FetchEntry(fetch_entry_data)
            }
            ClientToLib3h::PublishEntry(provided_entry_data) => {
                Lib3hClientProtocol::PublishEntry(provided_entry_data)
            }
            ClientToLib3h::QueryEntry(query_entry_data) => {
                Lib3hClientProtocol::QueryEntry(query_entry_data)
            }
        }
    }
}

impl From<Lib3hToClientResponse> for Lib3hClientProtocol {
    fn from(c: Lib3hToClientResponse) -> Self {
        match c {
            Lib3hToClientResponse::HandleSendDirectMessageResult(direct_message_data) => {
                Lib3hClientProtocol::HandleSendDirectMessageResult(direct_message_data)
            }
            Lib3hToClientResponse::HandleFetchEntryResult(fetch_entry_result_data) => {
                Lib3hClientProtocol::HandleFetchEntryResult(fetch_entry_result_data)
            }
            Lib3hToClientResponse::HandleQueryEntryResult(query_entry_result_data) => {
                Lib3hClientProtocol::HandleQueryEntryResult(query_entry_result_data)
            }
            Lib3hToClientResponse::HandleGetAuthoringEntryListResult(entry_list_data) => {
                Lib3hClientProtocol::HandleGetAuthoringEntryListResult(entry_list_data)
            }
            Lib3hToClientResponse::HandleGetGossipingEntryListResult(entry_list_data) => {
                Lib3hClientProtocol::HandleGetGossipingEntryListResult(entry_list_data)
            }
            variant => panic!("{:?} can't convert to Lib3hClientProtocol", variant),
        }
    }
}

impl From<Lib3hToClient> for Lib3hServerProtocol {
    fn from(c: Lib3hToClient) -> Self {
        match c {
            Lib3hToClient::Connected(connected_data) => {
                Lib3hServerProtocol::Connected(connected_data)
            }
            Lib3hToClient::Unbound(_unbound_data) => {
                Lib3hServerProtocol::Disconnected(DisconnectedData {
                    network_id: NetworkHash::default(),
                })
            }
            Lib3hToClient::SendDirectMessageResult(direct_message_data) => {
                Lib3hServerProtocol::SendDirectMessageResult(direct_message_data)
            }
            Lib3hToClient::HandleSendDirectMessage(direct_message_data) => {
                Lib3hServerProtocol::HandleSendDirectMessage(direct_message_data)
            }
            Lib3hToClient::HandleFetchEntry(fetch_entry_data) => {
                Lib3hServerProtocol::HandleFetchEntry(fetch_entry_data)
            }
            Lib3hToClient::HandleStoreEntryAspect(store_entry_aspect_data) => {
                Lib3hServerProtocol::HandleStoreEntryAspect(store_entry_aspect_data)
            }
            Lib3hToClient::HandleDropEntry(drop_entry_data) => {
                Lib3hServerProtocol::HandleDropEntry(drop_entry_data)
            }
            Lib3hToClient::HandleQueryEntry(query_entry_data) => {
                Lib3hServerProtocol::HandleQueryEntry(query_entry_data)
            }
            Lib3hToClient::HandleGetAuthoringEntryList(get_list_data) => {
                Lib3hServerProtocol::HandleGetAuthoringEntryList(get_list_data)
            }
            Lib3hToClient::HandleGetGossipingEntryList(get_list_data) => {
                Lib3hServerProtocol::HandleGetGossipingEntryList(get_list_data)
            }
        }
    }
}

impl From<ClientToLib3hResponse> for Lib3hServerProtocol {
    fn from(c: ClientToLib3hResponse) -> Self {
        match c {
            ClientToLib3hResponse::SendDirectMessageResult(direct_message_data) => {
                Lib3hServerProtocol::SendDirectMessageResult(direct_message_data)
            }
            ClientToLib3hResponse::FetchEntryResult(fetch_entry_result_data) => {
                Lib3hServerProtocol::FetchEntryResult(fetch_entry_result_data)
            }

            ClientToLib3hResponse::QueryEntryResult(query_entry_result_data) => {
                Lib3hServerProtocol::QueryEntryResult(query_entry_result_data)
            }
            ClientToLib3hResponse::BootstrapSuccess => {
                Lib3hServerProtocol::Connected(ConnectedData {
                    request_id: String::new(),
                    uri: Lib3hUri::with_undefined(),
                })
            }
            variant => panic!("{:?} can't convert to Lib3hServerProtocol", variant),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::convert::TryInto;
    use url::Url;

    fn connect_data() -> ConnectData {
        ConnectData {
            request_id: "".to_string(),
            peer_location: Url::parse("wss://192.168.0.102:58081/").unwrap().into(),
            network_id: "network_id".into(),
        }
    }

    #[test]
    fn test_translate_protocol() {
        let d = connect_data();
        let s = Lib3hClientProtocol::Connect(d.clone());
        let to_c: ClientToLib3h = s.clone().try_into().expect("A ClientToLib3h protocol");
        assert_eq!(
            to_c,
            ClientToLib3h::Bootstrap(BootstrapData {
                bootstrap_uri: Url::parse("wss://192.168.0.102:58081/").unwrap().into(),
                network_or_space_address: "network_id".into(),
            })
        );

        let to_s: Lib3hClientProtocol = to_c.into();
        assert_eq!(to_s, s);
    }
}