mod error;
#[cfg(feature = "admin-service-event-client-actix-web-client")]
mod ws;
use super::ProposalSlice;
use std::cmp;
use std::thread;
use std::time::{Duration, Instant};
pub use error::{NextEventError, WaitForError};
#[cfg(feature = "admin-service-event-client-actix-web-client")]
pub use ws::actix_web_client::{
AwcAdminServiceEventClient, AwcAdminServiceEventClientBuilder,
RunnableAwcAdminServiceEventClient,
};
#[derive(Clone, PartialEq)]
#[repr(transparent)]
pub struct PublicKey(pub Vec<u8>);
impl std::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str(&crate::hex::to_hex(&self.0))
}
}
#[derive(Clone, Debug)]
pub struct AdminServiceEvent {
event_id: u64,
event_type: EventType,
proposal: ProposalSlice,
}
#[derive(Clone, Debug, PartialEq)]
pub enum EventType {
ProposalSubmitted,
ProposalVote { requester: PublicKey },
ProposalAccepted { requester: PublicKey },
ProposalRejected { requester: PublicKey },
CircuitReady,
CircuitDisbanded,
}
impl AdminServiceEvent {
pub fn event_id(&self) -> &u64 {
&self.event_id
}
pub fn event_type(&self) -> &EventType {
&self.event_type
}
pub fn proposal(&self) -> &ProposalSlice {
&self.proposal
}
}
pub enum EventQuery<'a> {
ProposalSubmitted { circuit_id: &'a str },
ProposalVote { circuit_id: &'a str, key: PublicKey },
ProposalAccepted { circuit_id: &'a str, key: PublicKey },
ProposalRejected { circuit_id: &'a str, key: PublicKey },
CircuitReady { circuit_id: &'a str },
CircuitDisbanded { circuit_id: &'a str },
}
impl<'a> EventQuery<'a> {
fn filter(self) -> impl Fn(&AdminServiceEvent) -> bool + 'a {
move |event: &AdminServiceEvent| match &self {
EventQuery::ProposalSubmitted { circuit_id } => {
event.event_type() == &EventType::ProposalSubmitted
&& &event.proposal().circuit_id == circuit_id
}
EventQuery::ProposalVote { circuit_id, key } => match event.event_type() {
EventType::ProposalVote { requester } => {
requester == key && &event.proposal().circuit_id == circuit_id
}
_ => false,
},
EventQuery::ProposalAccepted { circuit_id, key } => match event.event_type() {
EventType::ProposalAccepted { requester } => {
requester == key && &event.proposal().circuit_id == circuit_id
}
_ => false,
},
EventQuery::ProposalRejected { circuit_id, key } => match event.event_type() {
EventType::ProposalRejected { requester } => {
requester == key && &event.proposal().circuit_id == circuit_id
}
_ => false,
},
EventQuery::CircuitReady { circuit_id } => {
event.event_type() == &EventType::CircuitReady
&& &event.proposal().circuit_id == circuit_id
}
EventQuery::CircuitDisbanded { circuit_id } => {
event.event_type() == &EventType::CircuitDisbanded
&& &event.proposal().circuit_id == circuit_id
}
}
}
}
pub trait AdminServiceEventClient {
fn try_next_event(&self) -> Result<Option<AdminServiceEvent>, NextEventError>;
fn next_event(&self) -> Result<AdminServiceEvent, NextEventError>;
fn wait_for_filter(
&self,
event_filter: &dyn Fn(&AdminServiceEvent) -> bool,
timeout: Duration,
) -> Result<AdminServiceEvent, WaitForError> {
let start = Instant::now();
let poll_rate = Duration::from_millis(100);
loop {
if let Some(event) = self
.try_next_event()
.map_err(WaitForError::NextEventError)?
{
if event_filter(&event) {
return Ok(event);
}
}
let elapsed = start.elapsed();
if timeout < elapsed {
return Err(WaitForError::TimeoutError);
}
let timeleft = timeout - elapsed;
let sleep_duration = cmp::min(timeleft, poll_rate);
thread::sleep(sleep_duration);
}
}
fn wait_for(
&self,
event_query: EventQuery,
timeout: Duration,
) -> Result<AdminServiceEvent, WaitForError> {
self.wait_for_filter(&event_query.filter(), timeout)
}
}
impl AdminServiceEventClient for Box<dyn AdminServiceEventClient> {
fn try_next_event(&self) -> Result<Option<AdminServiceEvent>, NextEventError> {
(**self).try_next_event()
}
fn next_event(&self) -> Result<AdminServiceEvent, NextEventError> {
(**self).next_event()
}
}
pub struct BlockingAdminServiceEventIterator<T>
where
T: AdminServiceEventClient,
{
client: T,
}
impl<T> BlockingAdminServiceEventIterator<T>
where
T: AdminServiceEventClient,
{
pub fn new(client: T) -> BlockingAdminServiceEventIterator<T> {
Self { client }
}
}
impl<T> Iterator for BlockingAdminServiceEventIterator<T>
where
T: AdminServiceEventClient,
{
type Item = AdminServiceEvent;
fn next(&mut self) -> Option<Self::Item> {
self.client.next_event().ok()
}
}