2020-07-01 09:51:37 +00:00
|
|
|
use client::{
|
2021-02-21 23:48:30 +00:00
|
|
|
addr::ConnectionArgs,
|
|
|
|
error::{Error as ClientError, NetworkConnectError, NetworkError},
|
2021-04-22 17:27:38 +00:00
|
|
|
Client, ServerInfo,
|
2020-07-01 09:51:37 +00:00
|
|
|
};
|
2021-05-31 17:03:18 +00:00
|
|
|
use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError};
|
2020-02-01 20:39:39 +00:00
|
|
|
use std::{
|
|
|
|
sync::{
|
2021-08-10 13:55:58 +00:00
|
|
|
atomic::{AtomicBool, Ordering},
|
2020-02-01 20:39:39 +00:00
|
|
|
Arc,
|
|
|
|
},
|
|
|
|
time::Duration,
|
|
|
|
};
|
2021-02-21 23:48:30 +00:00
|
|
|
use tokio::runtime;
|
2020-11-22 08:12:08 +00:00
|
|
|
use tracing::{trace, warn};
|
2019-04-14 23:28:29 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-07-11 18:41:52 +00:00
|
|
|
#[allow(clippy::enum_variant_names)] //TODO: evaluate ClientError ends with Enum name
|
2019-04-14 23:28:29 +00:00
|
|
|
pub enum Error {
|
2021-04-22 17:27:38 +00:00
|
|
|
ClientError {
|
|
|
|
error: ClientError,
|
|
|
|
mismatched_server_info: Option<ServerInfo>,
|
|
|
|
},
|
2019-05-07 11:09:50 +00:00
|
|
|
ClientCrashed,
|
2021-06-16 06:51:09 +00:00
|
|
|
ServerNotFound,
|
2019-04-14 23:28:29 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 19:47:36 +00:00
|
|
|
#[allow(clippy::large_enum_variant)] // TODO: Pending review in #587
|
2020-01-02 08:43:45 +00:00
|
|
|
pub enum Msg {
|
|
|
|
IsAuthTrusted(String),
|
|
|
|
Done(Result<Client, Error>),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct AuthTrust(String, bool);
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
// Used to asynchronously parse the server address, resolve host names,
|
2020-02-01 20:39:39 +00:00
|
|
|
// and create the client (which involves establishing a connection to the
|
|
|
|
// server).
|
2019-04-14 23:28:29 +00:00
|
|
|
pub struct ClientInit {
|
2020-01-02 08:43:45 +00:00
|
|
|
rx: Receiver<Msg>,
|
|
|
|
trust_tx: Sender<AuthTrust>,
|
2019-10-18 20:05:37 +00:00
|
|
|
cancel: Arc<AtomicBool>,
|
2019-04-14 23:28:29 +00:00
|
|
|
}
|
|
|
|
impl ClientInit {
|
2019-08-08 16:05:38 +00:00
|
|
|
pub fn new(
|
2021-05-17 17:32:26 +00:00
|
|
|
connection_args: ConnectionArgs,
|
2020-01-11 21:04:49 +00:00
|
|
|
username: String,
|
2019-08-08 16:05:38 +00:00
|
|
|
password: String,
|
2021-08-10 13:55:58 +00:00
|
|
|
runtime: Arc<runtime::Runtime>,
|
2019-08-08 16:05:38 +00:00
|
|
|
) -> Self {
|
2019-08-15 22:07:09 +00:00
|
|
|
let (tx, rx) = unbounded();
|
2020-01-02 08:43:45 +00:00
|
|
|
let (trust_tx, trust_rx) = unbounded();
|
2019-10-18 20:05:37 +00:00
|
|
|
let cancel = Arc::new(AtomicBool::new(false));
|
|
|
|
let cancel2 = Arc::clone(&cancel);
|
2019-04-14 23:28:29 +00:00
|
|
|
|
2021-02-18 00:01:57 +00:00
|
|
|
let runtime2 = Arc::clone(&runtime);
|
|
|
|
|
|
|
|
runtime.spawn(async move {
|
2021-02-21 23:48:30 +00:00
|
|
|
let trust_fn = |auth_server: &str| {
|
|
|
|
let _ = tx.send(Msg::IsAuthTrusted(auth_server.to_string()));
|
|
|
|
trust_rx
|
|
|
|
.recv()
|
2021-07-09 19:33:07 +00:00
|
|
|
.map(|AuthTrust(server, trust)| trust && server == *auth_server)
|
2021-02-21 23:48:30 +00:00
|
|
|
.unwrap_or(false)
|
2021-02-18 00:01:57 +00:00
|
|
|
};
|
2021-02-21 23:48:30 +00:00
|
|
|
|
2021-02-18 00:01:57 +00:00
|
|
|
let mut last_err = None;
|
|
|
|
|
|
|
|
const FOUR_MINUTES_RETRIES: u64 = 48;
|
|
|
|
'tries: for _ in 0..FOUR_MINUTES_RETRIES {
|
|
|
|
if cancel2.load(Ordering::Relaxed) {
|
|
|
|
break;
|
|
|
|
}
|
2021-04-22 17:27:38 +00:00
|
|
|
let mut mismatched_server_info = None;
|
2021-02-21 23:48:30 +00:00
|
|
|
match Client::new(
|
|
|
|
connection_args.clone(),
|
|
|
|
Arc::clone(&runtime2),
|
2021-04-22 17:27:38 +00:00
|
|
|
&mut mismatched_server_info,
|
2021-02-21 23:48:30 +00:00
|
|
|
)
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Ok(mut client) => {
|
|
|
|
if let Err(e) = client.register(username, password, trust_fn).await {
|
2021-04-22 17:27:38 +00:00
|
|
|
last_err = Some(Error::ClientError {
|
|
|
|
error: e,
|
|
|
|
mismatched_server_info: None,
|
|
|
|
});
|
2021-02-18 00:01:57 +00:00
|
|
|
break 'tries;
|
2021-02-21 23:48:30 +00:00
|
|
|
}
|
|
|
|
let _ = tx.send(Msg::Done(Ok(client)));
|
2021-03-29 08:34:33 +00:00
|
|
|
tokio::task::block_in_place(move || drop(runtime2));
|
2021-02-21 23:48:30 +00:00
|
|
|
return;
|
|
|
|
},
|
|
|
|
Err(ClientError::NetworkErr(NetworkError::ConnectFailed(
|
|
|
|
NetworkConnectError::Io(e),
|
|
|
|
))) => {
|
|
|
|
warn!(?e, "Failed to connect to the server. Retrying...");
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
trace!(?e, "Aborting server connection attempt");
|
2021-04-22 17:27:38 +00:00
|
|
|
last_err = Some(Error::ClientError {
|
|
|
|
error: e,
|
|
|
|
mismatched_server_info,
|
|
|
|
});
|
2021-02-21 23:48:30 +00:00
|
|
|
break 'tries;
|
|
|
|
},
|
2021-02-18 00:01:57 +00:00
|
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
2019-04-14 23:28:29 +00:00
|
|
|
}
|
2021-02-18 00:01:57 +00:00
|
|
|
|
2021-06-16 06:51:09 +00:00
|
|
|
// Parsing/host name resolution successful but no connection succeeded
|
|
|
|
// If last_err is None this typically means there was no server up at the input
|
|
|
|
// address and all the attempts timed out.
|
|
|
|
let _ = tx.send(Msg::Done(Err(last_err.unwrap_or(Error::ServerNotFound))));
|
2021-02-21 23:48:30 +00:00
|
|
|
|
2021-02-22 17:47:05 +00:00
|
|
|
// Safe drop runtime
|
|
|
|
tokio::task::block_in_place(move || drop(runtime2));
|
2019-05-17 07:55:51 +00:00
|
|
|
});
|
2019-04-14 23:28:29 +00:00
|
|
|
|
2020-01-02 08:43:45 +00:00
|
|
|
ClientInit {
|
|
|
|
rx,
|
|
|
|
trust_tx,
|
|
|
|
cancel,
|
2021-02-18 00:01:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Poll if the thread is complete.
|
2020-02-01 20:39:39 +00:00
|
|
|
/// Returns None if the thread is still running, otherwise returns the
|
|
|
|
/// Result of client creation.
|
2020-01-02 08:43:45 +00:00
|
|
|
pub fn poll(&self) -> Option<Msg> {
|
2019-04-14 23:28:29 +00:00
|
|
|
match self.rx.try_recv() {
|
2020-01-02 08:43:45 +00:00
|
|
|
Ok(msg) => Some(msg),
|
2019-04-14 23:28:29 +00:00
|
|
|
Err(TryRecvError::Empty) => None,
|
2020-01-02 08:43:45 +00:00
|
|
|
Err(TryRecvError::Disconnected) => Some(Msg::Done(Err(Error::ClientCrashed))),
|
2019-04-14 23:28:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
|
2020-01-02 08:43:45 +00:00
|
|
|
/// Report trust status of auth server
|
|
|
|
pub fn auth_trust(&self, auth_server: String, trusted: bool) {
|
|
|
|
let _ = self.trust_tx.send(AuthTrust(auth_server, trusted));
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn cancel(&mut self) { self.cancel.store(true, Ordering::Relaxed); }
|
2019-10-18 20:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for ClientInit {
|
2020-02-01 20:39:39 +00:00
|
|
|
fn drop(&mut self) { self.cancel(); }
|
2019-04-14 23:28:29 +00:00
|
|
|
}
|