1use std::fmt::Debug;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use tokio::runtime::Handle;
7
8pub trait HttpService: Debug + Send + Sync + 'static {
14 fn call(
16 &self,
17 request: reqwest::Request,
18 ) -> Pin<Box<dyn Future<Output = Result<reqwest::Response, reqwest::Error>> + Send + '_>>;
19}
20
21#[derive(Debug, Clone)]
23pub struct ReqwestService(reqwest::Client);
24
25impl ReqwestService {
26 pub fn new(client: reqwest::Client) -> Self {
27 Self(client)
28 }
29}
30
31impl HttpService for ReqwestService {
32 fn call(
33 &self,
34 request: reqwest::Request,
35 ) -> Pin<Box<dyn Future<Output = Result<reqwest::Response, reqwest::Error>> + Send + '_>> {
36 Box::pin(self.0.execute(request))
37 }
38}
39
40#[derive(Debug)]
56pub struct SpawnService {
57 inner: Arc<dyn HttpService>,
58 handle: Handle,
59}
60
61impl SpawnService {
62 pub fn new(inner: Arc<dyn HttpService>, handle: Handle) -> Self {
63 Self { inner, handle }
64 }
65}
66
67impl HttpService for SpawnService {
68 fn call(
69 &self,
70 request: reqwest::Request,
71 ) -> Pin<Box<dyn Future<Output = Result<reqwest::Response, reqwest::Error>> + Send + '_>> {
72 let inner = Arc::clone(&self.inner);
73 let handle = self.handle.clone();
74 Box::pin(async move {
75 match handle.spawn(async move { inner.call(request).await }).await {
76 Ok(result) => result,
77 Err(join_err) => {
78 panic!("I/O runtime task failed: {join_err}")
83 }
84 }
85 })
86 }
87}
88
89pub(crate) fn make_service(
91 client: reqwest::Client,
92 runtime: Option<&Handle>,
93) -> Arc<dyn HttpService> {
94 let base: Arc<dyn HttpService> = Arc::new(ReqwestService::new(client));
95 match runtime {
96 Some(handle) => Arc::new(SpawnService::new(base, handle.clone())),
97 None => base,
98 }
99}