base_endpoint/
composite_endpoint.rs1use crate::{BindEndpoint, BindOptions, ConnectEndpoint, no_addresses, rollback};
5use base_scheduler::{Cancellation, OperationError, OperationResult, SocketClose};
6
7#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct CompositeEndpoint<E> {
10 endpoints: Vec<E>,
11}
12
13impl<E> CompositeEndpoint<E> {
14 pub fn new(endpoints: Vec<E>) -> Self {
16 Self { endpoints }
17 }
18
19 pub fn endpoints(&self) -> &[E] {
21 &self.endpoints
22 }
23}
24
25impl<S, E> ConnectEndpoint<S> for CompositeEndpoint<E>
26where
27 S: Sync + ?Sized,
28 E: ConnectEndpoint<S>,
29{
30 type Connection = E::Connection;
31
32 async fn connect(
33 &self,
34 scheduler: &S,
35 cancellation: &Cancellation,
36 ) -> OperationResult<Self::Connection> {
37 cancellation.check()?;
38 let mut last_error = None;
39 for endpoint in &self.endpoints {
40 cancellation.check()?;
41 match endpoint.connect(scheduler, cancellation).await {
42 Ok(connection) => return Ok(connection),
43 Err(error @ OperationError::Cancelled(_)) => return Err(error),
44 Err(error) => last_error = Some(error),
45 }
46 }
47 Err(last_error.unwrap_or_else(no_addresses))
48 }
49}
50
51impl<S, E> BindEndpoint<S> for CompositeEndpoint<E>
53where
54 S: SocketClose<Socket = E::Listener> + ?Sized,
55 E: BindEndpoint<S>,
56{
57 type Listener = E::Listener;
58
59 async fn bind(
60 &self,
61 scheduler: &S,
62 options: BindOptions,
63 cancellation: &Cancellation,
64 ) -> OperationResult<Vec<Self::Listener>> {
65 cancellation.check()?;
66 if self.endpoints.is_empty() {
67 return Err(no_addresses());
68 }
69 let mut listeners = Vec::new();
70 for endpoint in &self.endpoints {
71 let result = match cancellation.check() {
72 Ok(()) => endpoint.bind(scheduler, options, cancellation).await,
73 Err(error) => Err(error.into()),
74 };
75 match result {
76 Ok(mut bound) => listeners.append(&mut bound),
77 Err(error) => {
78 rollback(scheduler, listeners).await;
79 return Err(error);
80 }
81 }
82 }
83 Ok(listeners)
84 }
85}