1use std::future::Future;
4use std::marker::{Send, Sync};
5use std::pin::Pin;
6
7use async_stream::try_stream;
8use futures_util::{Stream, StreamExt};
9use jsonrpsee::core::client::{ClientT, Error, SubscriptionClientT};
10use jsonrpsee::proc_macros::rpc;
11
12use crate::{HeaderClient, custom_client_error};
13
14pub use celestia_types::fraud_proof::{Proof, ProofType};
15
16mod rpc {
17 use jsonrpsee::core::{RpcResult, SubscriptionResult};
18
19 use super::*;
20
21 #[rpc(client, server, namespace = "fraud", namespace_separator = ".")]
23 pub trait Fraud {
24 #[method(name = "Get")]
26 async fn fraud_get(&self, proof_type: ProofType) -> RpcResult<Vec<Proof>>;
27 }
28
29 #[rpc(client, server, namespace = "fraud", namespace_separator = ".")]
31 pub trait FraudSubscription {
32 #[subscription(name = "Subscribe", unsubscribe = "Unsubscribe", item = Proof)]
34 async fn fraud_subscribe(&self, proof_type: ProofType) -> SubscriptionResult;
35 }
36}
37
38pub trait FraudClient: ClientT {
40 fn fraud_get<'a, 'fut>(
42 &'a self,
43 proof_type: ProofType,
44 ) -> impl Future<Output = Result<Vec<Proof>, Error>> + Send + 'fut
45 where
46 'a: 'fut,
47 Self: Sized + Sync + 'fut,
48 {
49 rpc::FraudClient::fraud_get(self, proof_type)
50 }
51
52 fn fraud_subscribe<'a>(
63 &'a self,
64 proof_type: ProofType,
65 ) -> Pin<Box<dyn Stream<Item = Result<Proof, Error>> + Send + 'a>>
66 where
67 Self: SubscriptionClientT + Sized + Sync,
68 {
69 try_stream! {
70 match rpc::FraudSubscriptionClient::fraud_subscribe(self, proof_type).await {
71 Ok(mut fraud_sub) => loop {
72 yield fraud_sub
73 .next()
74 .await
75 .ok_or_else(|| custom_client_error("unexpected end of stream"))??;
76 },
77 Err(Error::HttpNotImplemented) => {
78 let mut header_sub = HeaderClient::header_subscribe(self);
79 loop {
80 header_sub
82 .next()
83 .await
84 .ok_or_else(|| custom_client_error("unexpected end of stream"))??;
85
86 let proofs = rpc::FraudClient::fraud_get(self, proof_type).await?;
87 if !proofs.is_empty() {
88 for proof in proofs {
89 yield proof;
90 }
91
92 break;
96 }
97 }
98 }
99 err => {
100 err?;
101 }
102 };
103 }
104 .boxed()
105 }
106}
107
108impl<T> FraudClient for T where T: ClientT {}
109
110pub trait FraudServer: rpc::FraudServer + rpc::FraudSubscriptionServer {}
112
113impl<T> FraudServer for T where T: rpc::FraudServer + rpc::FraudSubscriptionServer {}
114
115pub use rpc::FraudServer as FraudRpcServer;
116pub use rpc::FraudSubscriptionServer as FraudSubscriptionRpcServer;