ic_web3_rs/transports/
either.rs

1//! A strongly-typed transport alternative.
2
3use crate::{api, error, rpc, BatchTransport, DuplexTransport, RequestId, Transport};
4use futures::{
5    future::{BoxFuture, FutureExt},
6    stream::{BoxStream, StreamExt},
7};
8use ic_cdk::api::management_canister::http_request::TransformContext;
9
10use super::ic_http_client::CallOptions;
11
12/// A wrapper over two possible transports.
13///
14/// This type can be used to write semi-generic
15/// code without the hassle of making all functions generic.
16///
17/// See the `examples` folder for an example how to use it.
18#[derive(Debug, Clone)]
19pub enum Either<A, B> {
20    /// First possible transport.
21    Left(A),
22    /// Second possible transport.
23    Right(B),
24}
25
26impl<A, B, AOut, BOut> Transport for Either<A, B>
27where
28    A: Transport<Out = AOut>,
29    B: Transport<Out = BOut>,
30    AOut: futures::Future<Output = error::Result<rpc::Value>> + 'static + Send,
31    BOut: futures::Future<Output = error::Result<rpc::Value>> + 'static + Send,
32{
33    type Out = BoxFuture<'static, error::Result<rpc::Value>>;
34
35    fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
36        match *self {
37            Self::Left(ref a) => a.prepare(method, params),
38            Self::Right(ref b) => b.prepare(method, params),
39        }
40    }
41
42    fn send(&self, id: RequestId, request: rpc::Call, options: CallOptions) -> Self::Out {
43        match *self {
44            Self::Left(ref a) => a.send(id, request, options).boxed(),
45            Self::Right(ref b) => b.send(id, request, options).boxed(),
46        }
47    }
48
49    fn set_max_response_bytes(&mut self, v: u64) {
50        match *self {
51            Self::Left(ref mut a) => a.set_max_response_bytes(v),
52            Self::Right(ref mut b) => b.set_max_response_bytes(v),
53        }
54    }
55}
56
57impl<A, B, ABatch, BBatch> BatchTransport for Either<A, B>
58where
59    A: BatchTransport<Batch = ABatch>,
60    B: BatchTransport<Batch = BBatch>,
61    A::Out: 'static + Send,
62    B::Out: 'static + Send,
63    ABatch: futures::Future<Output = error::Result<Vec<error::Result<rpc::Value>>>> + 'static + Send,
64    BBatch: futures::Future<Output = error::Result<Vec<error::Result<rpc::Value>>>> + 'static + Send,
65{
66    type Batch = BoxFuture<'static, error::Result<Vec<error::Result<rpc::Value>>>>;
67
68    fn send_batch<T>(&self, requests: T) -> Self::Batch
69    where
70        T: IntoIterator<Item = (RequestId, rpc::Call)>,
71    {
72        match *self {
73            Self::Left(ref a) => a.send_batch(requests).boxed(),
74            Self::Right(ref b) => b.send_batch(requests).boxed(),
75        }
76    }
77}
78
79impl<A, B, AStream, BStream> DuplexTransport for Either<A, B>
80where
81    A: DuplexTransport<NotificationStream = AStream>,
82    B: DuplexTransport<NotificationStream = BStream>,
83    A::Out: 'static + Send,
84    B::Out: 'static + Send,
85    AStream: futures::Stream<Item = rpc::Value> + 'static + Send,
86    BStream: futures::Stream<Item = rpc::Value> + 'static + Send,
87{
88    type NotificationStream = BoxStream<'static, rpc::Value>;
89
90    fn subscribe(&self, id: api::SubscriptionId) -> error::Result<Self::NotificationStream> {
91        Ok(match *self {
92            Self::Left(ref a) => a.subscribe(id)?.boxed(),
93            Self::Right(ref b) => b.subscribe(id)?.boxed(),
94        })
95    }
96
97    fn unsubscribe(&self, id: api::SubscriptionId) -> error::Result {
98        match *self {
99            Self::Left(ref a) => a.unsubscribe(id),
100            Self::Right(ref b) => b.unsubscribe(id),
101        }
102    }
103}