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
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct ServiceList {
    pub trusted: Vec<String>,
    pub untrusted: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct Address {
    pub address: String,
}

#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PingResponse {
    pub ack: bool,
}
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RegisterResponse {
    pub session: Option<Session>,
}

#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Session {
    pub token: Uuid,
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct ServiceIdentity {
    pub protocol: String,
    pub address: String,
}

#[cfg(feature = "discover")]
pub mod discover {

    use super::{PingResponse, RegisterResponse, ServiceIdentity};
    use reqwest;
    use reqwest::Client;
    use std::thread::sleep;
    use std::time::Duration;

    pub fn get_peers(api_path: &str, protocol: &str) -> Result<super::ServiceList, reqwest::Error> {
        reqwest::get(&format!("{}/discover/{}", api_path, protocol))?.json()
    }

    #[derive(Debug)]
    pub enum RegisterError {
        RegisterRefused,
        RegisterExpired,
        RequestError(reqwest::Error),
    }

    impl std::fmt::Display for RegisterError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match &self {
                RegisterError::RegisterRefused => write!(f, "register refused"),
                RegisterError::RegisterExpired => write!(f, "register revoked by server"),
                RegisterError::RequestError(e) => write!(f, "request failed: {}", e),
            }
        }
    }
    impl std::error::Error for RegisterError {}
    impl From<reqwest::Error> for RegisterError {
        fn from(err: reqwest::Error) -> RegisterError {
            RegisterError::RequestError(err)
        }
    }

    pub fn register(api_path: &str, id: ServiceIdentity) -> Result<(), RegisterError> {
        let client = Client::new();
        let (address, protocol) = (
            super::Address {
                address: id.address,
            },
            id.protocol,
        );
        let session: RegisterResponse = client
            .post(&format!("{}/discover/{}", api_path, protocol))
            .json(&address)
            .send()?
            .json()?;
        let session = match session.session {
            Some(s) => s,
            None => return Err(RegisterError::RegisterRefused),
        };
        loop {
            let resp: PingResponse = client
                .put(&format!("{}/ping/{}", api_path, session.token))
                .send()?
                .json()?;
            if !resp.ack {
                return Err(RegisterError::RegisterExpired);
            }
            sleep(Duration::from_secs(50));
        }
    }
}