bim-core 0.15.4

Client core for bench.im.
Documentation
use std::io::{Read, Write};
use std::net::{SocketAddr, TcpStream};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[cfg(debug_assertions)]
use log::debug;

use rustls::{OwnedTrustAnchor, RootCertStore};
use url::Url;

use crate::utils::SpeedTestResult;

pub trait GenericStream: Read + Write {}

impl<T: Read + Write> GenericStream for T {}

pub fn make_connection(
    address: &SocketAddr,
    url: &Url,
) -> Result<Box<dyn GenericStream>, String> {
    let ssl = if url.scheme() == "https" { true } else { false };
    let mut retry = 3;

    while retry > 0 {
        if let Ok(stream) = TcpStream::connect_timeout(&address, Duration::from_micros(3_000_000)) {
            #[cfg(debug_assertions)]
            debug!("TCP connected");

            let _r = stream.set_write_timeout(Some(Duration::from_secs(3)));
            let _r = stream.set_read_timeout(Some(Duration::from_secs(3)));
            if !ssl {
                return Ok(Box::new(stream));
            }

            let mut root_store = RootCertStore::empty();
            root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(
                |ta| {
                    OwnedTrustAnchor::from_subject_spki_name_constraints(
                        ta.subject,
                        ta.spki,
                        ta.name_constraints,
                    )
                },
            ));
            let config = rustls::ClientConfig::builder()
                .with_safe_defaults()
                .with_root_certificates(root_store)
                .with_no_client_auth();

            let server_name = url.host_str().unwrap().try_into().unwrap();
            let conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap();
            let tls = rustls::StreamOwned::new(conn, stream);

            #[cfg(debug_assertions)]
            debug!("SSL connected");

            return Ok(Box::new(tls));
        }

        retry -= 1;
    }
    return Err(String::from("连接失败"));
}

pub trait Client {
    fn result(&self) -> SpeedTestResult;

    fn ping(&mut self) -> bool;

    fn upload(&mut self) -> bool;

    fn download(&mut self) -> bool;

    fn run(&mut self) -> bool {
        let r = self.ping();
        if r {
            thread::sleep(Duration::from_secs(2));
            self.upload();
            thread::sleep(Duration::from_secs(3));
            self.download();
            return true;
        }
        false
    }
}