rename to ClientConfig
This commit is contained in:
parent
0b6b853662
commit
0b88df1367
3 changed files with 32 additions and 29 deletions
|
@ -15,21 +15,23 @@ use tokio::{
|
||||||
sync::{mpsc, oneshot},
|
sync::{mpsc, oneshot},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
};
|
};
|
||||||
use tokio_rustls::{client::TlsStream, rustls::ClientConfig, webpki::DNSNameRef, TlsConnector};
|
use tokio_rustls::{
|
||||||
|
client::TlsStream, rustls::ClientConfig as RustlsConfig, webpki::DNSNameRef, TlsConnector,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::types::Response;
|
use crate::types::Response;
|
||||||
|
|
||||||
use super::ClientNotConnected;
|
use super::ClientConfig;
|
||||||
|
|
||||||
pub type BoxedFunc = Box<dyn Fn()>;
|
pub type BoxedFunc = Box<dyn Fn()>;
|
||||||
pub type ResultMap = Arc<RwLock<HashMap<usize, (Option<String>, Option<Waker>)>>>;
|
pub type ResultMap = Arc<RwLock<HashMap<usize, (Option<String>, Option<Waker>)>>>;
|
||||||
pub type GreetingRx = Arc<RwLock<(bool, Option<Waker>)>>;
|
pub type GreetingState = Arc<RwLock<(bool, Option<Waker>)>>;
|
||||||
pub const TAG_PREFIX: &str = "panorama";
|
pub const TAG_PREFIX: &str = "panorama";
|
||||||
|
|
||||||
/// The lower-level Client struct, that is shared by all of the exported structs in the state machine.
|
/// The lower-level Client struct, that is shared by all of the exported structs in the state machine.
|
||||||
pub struct Client<C> {
|
pub struct Client<C> {
|
||||||
config: ClientNotConnected,
|
config: ClientConfig,
|
||||||
conn: WriteHalf<C>,
|
conn: WriteHalf<C>,
|
||||||
symbols: StringStore,
|
symbols: StringStore,
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ pub struct Client<C> {
|
||||||
exit_tx: mpsc::Sender<()>,
|
exit_tx: mpsc::Sender<()>,
|
||||||
|
|
||||||
/// used for receiving the greeting
|
/// used for receiving the greeting
|
||||||
greeting: GreetingRx,
|
greeting: GreetingState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> Client<C>
|
impl<C> Client<C>
|
||||||
|
@ -54,7 +56,7 @@ where
|
||||||
C: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
C: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||||
{
|
{
|
||||||
/// Creates a new client that wraps a connection
|
/// Creates a new client that wraps a connection
|
||||||
pub fn new(conn: C, config: ClientNotConnected) -> Self {
|
pub fn new(conn: C, config: ClientConfig) -> Self {
|
||||||
let (read_half, write_half) = io::split(conn);
|
let (read_half, write_half) = io::split(conn);
|
||||||
let results = Arc::new(RwLock::new(HashMap::new()));
|
let results = Arc::new(RwLock::new(HashMap::new()));
|
||||||
let (exit_tx, exit_rx) = mpsc::channel(1);
|
let (exit_tx, exit_rx) = mpsc::channel(1);
|
||||||
|
@ -79,9 +81,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_for_greeting(&self) -> GreetingHandler {
|
/// Returns a future that doesn't resolve until we receive a greeting from the server.
|
||||||
|
pub fn wait_for_greeting(&self) -> GreetingWaiter {
|
||||||
debug!("waiting for greeting");
|
debug!("waiting for greeting");
|
||||||
GreetingHandler(self.greeting.clone())
|
GreetingWaiter(self.greeting.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a command to the server and returns a handle to retrieve the result
|
/// Sends a command to the server and returns a handle to retrieve the result
|
||||||
|
@ -100,7 +103,7 @@ where
|
||||||
self.conn.flush().await?;
|
self.conn.flush().await?;
|
||||||
debug!("[{}] written.", id);
|
debug!("[{}] written.", id);
|
||||||
|
|
||||||
ExecHandle(self, id).await;
|
ExecWaiter(self, id).await;
|
||||||
let resp = {
|
let resp = {
|
||||||
let mut handlers = self.results.write();
|
let mut handlers = self.results.write();
|
||||||
handlers.remove(&id).unwrap().0.unwrap()
|
handlers.remove(&id).unwrap().0.unwrap()
|
||||||
|
@ -142,7 +145,7 @@ where
|
||||||
|
|
||||||
let server_name = &self.config.hostname;
|
let server_name = &self.config.hostname;
|
||||||
|
|
||||||
let mut tls_config = ClientConfig::new();
|
let mut tls_config = RustlsConfig::new();
|
||||||
tls_config
|
tls_config
|
||||||
.root_store
|
.root_store
|
||||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
|
@ -154,9 +157,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GreetingHandler(GreetingRx);
|
pub struct GreetingWaiter(GreetingState);
|
||||||
|
|
||||||
impl Future for GreetingHandler {
|
impl Future for GreetingWaiter {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
let (state, waker) = &mut *self.0.write();
|
let (state, waker) = &mut *self.0.write();
|
||||||
|
@ -171,9 +174,9 @@ impl Future for GreetingHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExecHandle<'a, C>(&'a Client<C>, usize);
|
pub struct ExecWaiter<'a, C>(&'a Client<C>, usize);
|
||||||
|
|
||||||
impl<'a, C> Future for ExecHandle<'a, C> {
|
impl<'a, C> Future for ExecWaiter<'a, C> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
let mut handlers = self.0.results.write();
|
let mut handlers = self.0.results.write();
|
||||||
|
@ -198,7 +201,7 @@ async fn listen<C>(
|
||||||
conn: C,
|
conn: C,
|
||||||
results: ResultMap,
|
results: ResultMap,
|
||||||
mut exit: mpsc::Receiver<()>,
|
mut exit: mpsc::Receiver<()>,
|
||||||
greeting: GreetingRx,
|
greeting: GreetingState,
|
||||||
) -> Result<C>
|
) -> Result<C>
|
||||||
where
|
where
|
||||||
C: AsyncRead + Unpin,
|
C: AsyncRead + Unpin,
|
||||||
|
@ -225,7 +228,7 @@ where
|
||||||
|
|
||||||
if tag == "*" {
|
if tag == "*" {
|
||||||
debug!("UNTAGGED {:?}", rest);
|
debug!("UNTAGGED {:?}", rest);
|
||||||
|
|
||||||
// TODO: verify that the greeting is actually an OK
|
// TODO: verify that the greeting is actually an OK
|
||||||
if let Some(greeting) = greeting.take() {
|
if let Some(greeting) = greeting.take() {
|
||||||
let (greeting, waker) = &mut *greeting.write();
|
let (greeting, waker) = &mut *greeting.write();
|
||||||
|
|
|
@ -15,11 +15,10 @@ mod inner;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tokio::{
|
use tokio::net::TcpStream;
|
||||||
io::{self, AsyncRead, AsyncWrite, ReadHalf, WriteHalf},
|
use tokio_rustls::{
|
||||||
net::TcpStream,
|
client::TlsStream, rustls::ClientConfig as RustlsConfig, webpki::DNSNameRef, TlsConnector,
|
||||||
};
|
};
|
||||||
use tokio_rustls::{client::TlsStream, rustls::ClientConfig, webpki::DNSNameRef, TlsConnector};
|
|
||||||
|
|
||||||
pub use self::inner::Client;
|
pub use self::inner::Client;
|
||||||
|
|
||||||
|
@ -28,13 +27,13 @@ pub use self::inner::Client;
|
||||||
/// Call [`.build`][1] to _build_ the config, then run [`.connect`][2] to actually start opening
|
/// Call [`.build`][1] to _build_ the config, then run [`.connect`][2] to actually start opening
|
||||||
/// the connection to the server.
|
/// the connection to the server.
|
||||||
///
|
///
|
||||||
/// [1]: self::ClientNotConnectedBuilder::build
|
/// [1]: self::ClientConfigBuilder::build
|
||||||
/// [2]: self::ClientNotConnected::connect
|
/// [2]: self::ClientConfig::connect
|
||||||
pub type ClientBuilder = ClientNotConnectedBuilder;
|
pub type ClientBuilder = ClientConfigBuilder;
|
||||||
|
|
||||||
/// An IMAP client that hasn't been connected yet.
|
/// An IMAP client that hasn't been connected yet.
|
||||||
#[derive(Builder, Clone, Debug)]
|
#[derive(Builder, Clone, Debug)]
|
||||||
pub struct ClientNotConnected {
|
pub struct ClientConfig {
|
||||||
/// The hostname of the IMAP server. If using TLS, must be an address
|
/// The hostname of the IMAP server. If using TLS, must be an address
|
||||||
hostname: String,
|
hostname: String,
|
||||||
|
|
||||||
|
@ -47,14 +46,14 @@ pub struct ClientNotConnected {
|
||||||
tls: bool,
|
tls: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientNotConnected {
|
impl ClientConfig {
|
||||||
pub async fn open(self) -> Result<ClientUnauthenticated> {
|
pub async fn open(self) -> Result<ClientUnauthenticated> {
|
||||||
let hostname = self.hostname.as_ref();
|
let hostname = self.hostname.as_ref();
|
||||||
let port = self.port;
|
let port = self.port;
|
||||||
let conn = TcpStream::connect((hostname, port)).await?;
|
let conn = TcpStream::connect((hostname, port)).await?;
|
||||||
|
|
||||||
if self.tls {
|
if self.tls {
|
||||||
let mut tls_config = ClientConfig::new();
|
let mut tls_config = RustlsConfig::new();
|
||||||
tls_config
|
tls_config
|
||||||
.root_store
|
.root_store
|
||||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
|
|
|
@ -6,7 +6,7 @@ mod imap2;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use panorama_imap::{
|
use panorama_imap::{
|
||||||
client::{ClientBuilder, ClientNotConnected},
|
client::{ClientBuilder, ClientConfig},
|
||||||
command::Command as ImapCommand,
|
command::Command as ImapCommand,
|
||||||
};
|
};
|
||||||
use tokio::{sync::mpsc::UnboundedReceiver, task::JoinHandle};
|
use tokio::{sync::mpsc::UnboundedReceiver, task::JoinHandle};
|
||||||
|
@ -69,7 +69,7 @@ pub async fn run_mail(
|
||||||
|
|
||||||
/// The main sequence of steps for the IMAP thread to follow
|
/// The main sequence of steps for the IMAP thread to follow
|
||||||
async fn imap_main(acct: MailAccountConfig) -> Result<()> {
|
async fn imap_main(acct: MailAccountConfig) -> Result<()> {
|
||||||
let builder: ClientNotConnected = ClientBuilder::default()
|
let builder: ClientConfig = ClientBuilder::default()
|
||||||
.hostname(acct.imap.server.clone())
|
.hostname(acct.imap.server.clone())
|
||||||
.port(acct.imap.port)
|
.port(acct.imap.port)
|
||||||
.tls(matches!(acct.imap.tls, TlsMethod::On))
|
.tls(matches!(acct.imap.tls, TlsMethod::On))
|
||||||
|
@ -79,7 +79,7 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> {
|
||||||
debug!("connecting to {}:{}", &acct.imap.server, acct.imap.port);
|
debug!("connecting to {}:{}", &acct.imap.server, acct.imap.port);
|
||||||
let unauth = builder.open().await?;
|
let unauth = builder.open().await?;
|
||||||
|
|
||||||
let unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
|
let mut unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
|
||||||
debug!("attempting to upgrade");
|
debug!("attempting to upgrade");
|
||||||
let client = unauth.upgrade().await?;
|
let client = unauth.upgrade().await?;
|
||||||
debug!("upgrade successful");
|
debug!("upgrade successful");
|
||||||
|
@ -90,6 +90,7 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> {
|
||||||
|
|
||||||
debug!("preparing to auth");
|
debug!("preparing to auth");
|
||||||
// check if the authentication method is supported
|
// check if the authentication method is supported
|
||||||
|
unauth.capabilities().await?;
|
||||||
|
|
||||||
// debug!("sending CAPABILITY");
|
// debug!("sending CAPABILITY");
|
||||||
// let result = unauth.capabilities().await?;
|
// let result = unauth.capabilities().await?;
|
||||||
|
|
Loading…
Reference in a new issue