libp2prs_infoserver/
lib.rs

1// Copyright 2020 Netwarps Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use libp2prs_core::PeerId;
22use libp2prs_runtime::task;
23use libp2prs_swarm::Control;
24use serde::{Deserialize, Serialize};
25use std::str::FromStr;
26use tide::http::mime;
27use tide::{Body, Request, Response, Server};
28
29#[macro_use]
30extern crate lazy_static;
31
32lazy_static! {
33    static ref NON_PARAM_ROUTE: Vec<String> = {
34        vec![
35            "".to_string(),
36            "/recv".to_string(),
37            "/send".to_string(),
38            "/peer".to_string(),
39            "/connection".to_string(),
40        ]
41    };
42    static ref PARAM_ROUTE: Vec<String> = vec!["/peer/_".to_string(), "/protocol?protocol_id=_".to_string()];
43}
44
45/// Response, message contains error info if statusCode isn't 200.
46#[derive(Serialize, Deserialize)]
47struct ResponseBody {
48    status: i64,
49    message: String,
50    result: Vec<String>,
51}
52
53/// Tide server
54pub struct InfoServer {
55    monitor: Server<Control>,
56    // map: HashMap<String, IRouteHandler>,
57}
58
59/// Save package count&size
60#[derive(Serialize, Deserialize)]
61struct PackageInfo {
62    package_count: usize,
63    package_bytes: usize,
64}
65
66/// Save package count&size by peer_id or protocol_id
67#[derive(Serialize, Deserialize)]
68struct SpecInfo {
69    package_in: usize,
70    package_out: usize,
71}
72
73/// A struct that deserialize protocol_id.
74#[derive(Serialize, Deserialize, Debug)]
75struct Protocol {
76    protocol_id: String,
77}
78
79/// A struct that deserialize peer_id.
80#[derive(Serialize, Deserialize, Debug)]
81struct Peer {
82    count: usize,
83}
84
85/// Save data from network_info.
86#[derive(Serialize, Deserialize, Debug)]
87struct NetworkConnectionStatus {
88    /// The total number of connections, both established and pending.
89    num_connections: usize,
90    /// The total number of pending connections, both incoming and outgoing.
91    num_connections_pending: usize,
92    /// The total number of established connections.
93    num_connections_established: usize,
94    /// The total number of active sub streams.
95    num_active_streams: usize,
96    /// The information of all established connections.
97    connection_info: Vec<NetworkConnectionInfo>,
98}
99
100/// A struct that save connection info.
101#[derive(Serialize, Deserialize, Debug)]
102struct NetworkConnectionInfo {
103    la: Vec<u8>,
104    ra: Vec<u8>,
105    local_peer_id: String,
106    remote_peer_id: String,
107    num_inbound_streams: usize,
108    num_outbound_streams: usize,
109}
110
111impl InfoServer {
112    pub fn new(control: Control) -> Self {
113        let mut monitor = tide::with_state(control);
114
115        monitor.at("").get(get_all);
116        monitor.at("/recv").get(get_recv_pkg);
117        monitor.at("/send").get(get_sent_pkg);
118        monitor.at("/protocol").get(get_protocol_info);
119        monitor.at("/peer").get(get_peer_count).at("/:peer_id").get(get_peer_info);
120        monitor.at("/connection").get(get_connection_info);
121
122        InfoServer { monitor }
123    }
124
125    pub fn start(self, addr: String) {
126        task::spawn(async move {
127            let r = self.monitor.listen(addr).await;
128            log::info!("Info server started result={:?}", r);
129        });
130    }
131}
132
133/// Return route list
134async fn get_all(req: Request<Control>) -> tide::Result {
135    let addr = req.local_addr().unwrap();
136
137    let mut available = "<h3>Available Endpoints:</h3></br>".to_string();
138    for item in NON_PARAM_ROUTE.iter() {
139        let route = addr.to_owned() + item;
140        available = available + &format!("<a href=//{}>{}</a></br>", route, route);
141    }
142
143    let mut argument = "<h3>Endpoints that require arguments:</h3></br>".to_string();
144    for item in PARAM_ROUTE.iter() {
145        let route = addr.to_owned() + item;
146        argument += &format!("<a href=//{}>{}</a></br>", route, route);
147    }
148
149    let res_body =
150        "<head><link rel=\"icon\" href=\"data:;base64,=\"></head>".to_string() + "<body>" + &available + &argument + "</body>";
151
152    let response = Response::builder(200).content_type(mime::HTML).body(res_body).build();
153    Ok(response)
154}
155
156/// Get peer count
157async fn get_peer_count(req: Request<Control>) -> tide::Result {
158    let mut control = req.state().clone();
159
160    let network_info = control.retrieve_networkinfo().await.map_err(|e| {
161        log::error!("{:?}", e);
162        tide::Error::new(500, e)
163    })?;
164
165    let peer = serde_json::to_string(&Peer {
166        count: network_info.num_peers,
167    })
168    .unwrap();
169
170    let result_body = Body::from_json(&ResponseBody {
171        status: 0,
172        message: "".to_string(),
173        result: vec![peer],
174    })?;
175    let response = Response::builder(200).body(result_body).build();
176    Ok(response)
177}
178
179/// Get connection info
180async fn get_connection_info(req: Request<Control>) -> tide::Result {
181    let mut control = req.state().clone();
182
183    let network_info = control.retrieve_networkinfo().await.map_err(|e| {
184        log::error!("{:?}", e);
185        tide::Error::new(500, e)
186    })?;
187    let cis = control.dump_connections(None).await.map_err(|e| {
188        log::error!("{:?}", e);
189        tide::Error::new(500, e)
190    })?;
191
192    let mut connection_info = Vec::new();
193    for item in cis {
194        let info = NetworkConnectionInfo {
195            la: item.info.la.to_vec(),
196            ra: item.info.ra.to_vec(),
197            local_peer_id: item.info.local_peer_id.to_string(),
198            remote_peer_id: item.info.remote_peer_id.to_string(),
199            num_inbound_streams: item.info.num_inbound_streams,
200            num_outbound_streams: item.info.num_outbound_streams,
201        };
202        connection_info.push(info);
203    }
204
205    let network_connection_status = NetworkConnectionStatus {
206        num_connections: network_info.num_connections,
207        num_connections_pending: network_info.num_connections_pending,
208        num_connections_established: network_info.num_connections_established,
209        num_active_streams: network_info.num_active_streams,
210        connection_info,
211    };
212
213    let result_body = Body::from_json(&ResponseBody {
214        status: 0,
215        message: "".to_string(),
216        result: vec![serde_json::to_string(&network_connection_status).unwrap()],
217    })?;
218    let response = Response::builder(200).body(result_body).build();
219    Ok(response)
220}
221
222/// Get received package counts and bytes
223async fn get_recv_pkg(req: Request<Control>) -> tide::Result {
224    let (package_count, package_bytes) = req.state().get_recv_count_and_size();
225
226    let package = PackageInfo {
227        package_count,
228        package_bytes,
229    };
230
231    let result_body = Body::from_json(&package)?;
232    let response = Response::builder(200).body(result_body).build();
233    Ok(response)
234}
235
236/// Get sent package counts and bytes
237async fn get_sent_pkg(req: Request<Control>) -> tide::Result {
238    let (package_count, package_bytes) = req.state().get_sent_count_and_size();
239
240    let package = PackageInfo {
241        package_count,
242        package_bytes,
243    };
244
245    let result_body = Body::from_json(&ResponseBody {
246        status: 0,
247        message: "".to_string(),
248        result: vec![serde_json::to_string(&package).unwrap()],
249    })?;
250    let response = Response::builder(200).body(result_body).build();
251    Ok(response)
252}
253
254/// Get sent&received package bytes by protocol_id
255async fn get_protocol_info(req: Request<Control>) -> tide::Result {
256    let protocol: Protocol = req.query()?;
257    let (receive, send) = req.state().get_protocol_in_and_out(&protocol.protocol_id);
258
259    let mut spec_info = SpecInfo {
260        package_in: 0,
261        package_out: 0,
262    };
263    if let Some(value) = receive {
264        spec_info.package_in = value
265    }
266    if let Some(value) = send {
267        spec_info.package_out = value
268    }
269
270    let result_body = Body::from_json(&ResponseBody {
271        status: 0,
272        message: "".to_string(),
273        result: vec![serde_json::to_string(&spec_info).unwrap()],
274    })?;
275    let response = Response::builder(200).body(result_body).build();
276    Ok(response)
277}
278
279/// Get sent&received package bytes by peer_id
280async fn get_peer_info(req: Request<Control>) -> tide::Result {
281    let peer = req.param("peer_id")?;
282    let peer_id = match PeerId::from_str(peer) {
283        Ok(info) => info,
284        Err(e) => {
285            let err_body = Body::from_json(&ResponseBody {
286                status: 1,
287                message: format!("Cannot parse : {:?}", e),
288                result: vec![],
289            })?;
290            return Ok(Response::builder(400).body(err_body).build());
291        }
292    };
293
294    let (receive, send) = req.state().get_peer_in_and_out(&peer_id);
295
296    let mut spec_info = SpecInfo {
297        package_in: 0,
298        package_out: 0,
299    };
300    if let Some(value) = receive {
301        spec_info.package_in = value
302    }
303    if let Some(value) = send {
304        spec_info.package_out = value
305    }
306
307    let result_body = Body::from_json(&ResponseBody {
308        status: 0,
309        message: "".to_string(),
310        result: vec![serde_json::to_string(&spec_info).unwrap()],
311    })?;
312    let response = Response::builder(200).body(result_body).build();
313    Ok(response)
314}