use futures::{try_ready, Future, Poll}; use state_machine_future::{transition, RentToOwn, StateMachineFuture}; use std::io; use crate::config::{Host, SslMode}; use crate::proto::{CancelQueryRawFuture, ConnectSocketFuture}; use crate::{Config, Error, MakeTlsConnect, Socket}; #[derive(StateMachineFuture)] pub enum CancelQuery where T: MakeTlsConnect, { #[state_machine_future(start, transitions(ConnectingSocket))] Start { tls: T, idx: Option, config: Config, process_id: i32, secret_key: i32, }, #[state_machine_future(transitions(Canceling))] ConnectingSocket { future: ConnectSocketFuture, mode: SslMode, tls: T::TlsConnect, process_id: i32, secret_key: i32, }, #[state_machine_future(transitions(Finished))] Canceling { future: CancelQueryRawFuture, }, #[state_machine_future(ready)] Finished(()), #[state_machine_future(error)] Failed(Error), } impl PollCancelQuery for CancelQuery where T: MakeTlsConnect, { fn poll_start<'a>(state: &'a mut RentToOwn<'a, Start>) -> Poll, Error> { let mut state = state.take(); let idx = state.idx.ok_or_else(|| { Error::connect(io::Error::new(io::ErrorKind::InvalidInput, "unknown host")) })?; let hostname = match &state.config.0.host[idx] { Host::Tcp(host) => &**host, // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Host::Unix(_) => "", }; let tls = state .tls .make_tls_connect(hostname) .map_err(|e| Error::tls(e.into()))?; transition!(ConnectingSocket { mode: state.config.0.ssl_mode, future: ConnectSocketFuture::new(state.config, idx), tls, process_id: state.process_id, secret_key: state.secret_key, }) } fn poll_connecting_socket<'a>( state: &'a mut RentToOwn<'a, ConnectingSocket>, ) -> Poll, Error> { let socket = try_ready!(state.future.poll()); let state = state.take(); transition!(Canceling { future: CancelQueryRawFuture::new( socket, state.mode, state.tls, state.process_id, state.secret_key ), }) } fn poll_canceling<'a>( state: &'a mut RentToOwn<'a, Canceling>, ) -> Poll { try_ready!(state.future.poll()); transition!(Finished(())) } } impl CancelQueryFuture where T: MakeTlsConnect, { pub fn new( tls: T, idx: Option, config: Config, process_id: i32, secret_key: i32, ) -> CancelQueryFuture { CancelQuery::start(tls, idx, config, process_id, secret_key) } }