@@ -8,12 +8,18 @@ use std::fmt::Debug;
8
8
use std:: future:: Future ;
9
9
10
10
/// An abstract HTTP client.
11
+ #[ cfg_attr( not( target_arch = "wasm32" ) , trait_variant:: make( Send ) ) ]
11
12
pub trait HttpClient {
12
13
/// Send an HTTP request and return the response.
13
14
fn send_http (
14
15
& self ,
15
16
request : Request < Vec < u8 > > ,
16
- ) -> impl Future < Output = core:: result:: Result < Response < Vec < u8 > > , Box < dyn std:: error:: Error + Send + Sync + ' static > > > + Send ;
17
+ ) -> impl Future <
18
+ Output = core:: result:: Result <
19
+ Response < Vec < u8 > > ,
20
+ Box < dyn std:: error:: Error + Send + Sync + ' static > ,
21
+ > ,
22
+ > ;
17
23
}
18
24
19
25
type XrpcResult < O , E > = core:: result:: Result < OutputDataOrBytes < O > , self :: Error < E > > ;
@@ -22,88 +28,120 @@ type XrpcResult<O, E> = core::result::Result<OutputDataOrBytes<O>, self::Error<E
22
28
///
23
29
/// [`send_xrpc()`](XrpcClient::send_xrpc) method has a default implementation,
24
30
/// which wraps the [`HttpClient::send_http()`]` method to handle input and output as an XRPC Request.
31
+ #[ cfg_attr( not( target_arch = "wasm32" ) , trait_variant:: make( Send ) ) ]
25
32
pub trait XrpcClient : HttpClient {
26
33
/// The base URI of the XRPC server.
27
34
fn base_uri ( & self ) -> String ;
28
35
/// Get the authentication token to use `Authorization` header.
29
36
#[ allow( unused_variables) ]
30
- fn authentication_token ( & self , is_refresh : bool ) -> impl Future < Output = Option < String > > + Send {
37
+ fn authentication_token ( & self , is_refresh : bool ) -> impl Future < Output = Option < String > > {
31
38
async { None }
32
39
}
33
40
/// Get the `atproto-proxy` header.
34
- fn atproto_proxy_header ( & self ) -> impl Future < Output = Option < String > > + Send {
41
+ fn atproto_proxy_header ( & self ) -> impl Future < Output = Option < String > > {
35
42
async { None }
36
43
}
37
44
/// Get the `atproto-accept-labelers` header.
38
- fn atproto_accept_labelers_header ( & self ) -> impl Future < Output = Option < Vec < String > > > + Send {
45
+ fn atproto_accept_labelers_header ( & self ) -> impl Future < Output = Option < Vec < String > > > {
39
46
async { None }
40
47
}
41
48
/// Send an XRPC request and return the response.
42
- fn send_xrpc < P , I , O , E > ( & self , request : & XrpcRequest < P , I > ) -> impl Future < Output = XrpcResult < O , E > > + Send
49
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
50
+ fn send_xrpc < P , I , O , E > (
51
+ & self ,
52
+ request : & XrpcRequest < P , I > ,
53
+ ) -> impl Future < Output = XrpcResult < O , E > >
43
54
where
44
55
P : Serialize + Send + Sync ,
45
56
I : Serialize + Send + Sync ,
46
57
O : DeserializeOwned + Send + Sync ,
47
58
E : DeserializeOwned + Send + Sync + Debug ,
59
+ // This code is duplicated because of this trait bound.
60
+ // `Self` has to be `Sync` for `Future` to be `Send`.
48
61
Self : Sync ,
49
62
{
50
- async {
51
- let mut uri = format ! ( "{}/xrpc/{}" , self . base_uri( ) , request. nsid) ;
52
- // Query parameters
53
- if let Some ( p) = & request. parameters {
54
- serde_html_form:: to_string ( p) . map ( |qs| {
55
- uri += "?" ;
56
- uri += & qs;
57
- } ) ?;
58
- } ;
59
- let mut builder = Request :: builder ( ) . method ( & request. method ) . uri ( & uri) ;
60
- // Headers
61
- if let Some ( encoding) = & request. encoding {
62
- builder = builder. header ( Header :: ContentType , encoding) ;
63
- }
64
- if let Some ( token) = self
65
- . authentication_token (
66
- request. method == Method :: POST && request. nsid == NSID_REFRESH_SESSION ,
67
- )
68
- . await
69
- {
70
- builder = builder. header ( Header :: Authorization , format ! ( "Bearer {}" , token) ) ;
71
- }
72
- if let Some ( proxy) = self . atproto_proxy_header ( ) . await {
73
- builder = builder. header ( Header :: AtprotoProxy , proxy) ;
74
- }
75
- if let Some ( accept_labelers) = self . atproto_accept_labelers_header ( ) . await {
76
- builder = builder. header ( Header :: AtprotoAcceptLabelers , accept_labelers. join ( ", " ) ) ;
77
- }
78
- // Body
79
- let body = if let Some ( input) = & request. input {
80
- match input {
81
- InputDataOrBytes :: Data ( data) => serde_json:: to_vec ( & data) ?,
82
- InputDataOrBytes :: Bytes ( bytes) => bytes. clone ( ) ,
83
- }
84
- } else {
85
- Vec :: new ( )
86
- } ;
87
- // Send
88
- let ( parts, body) =
89
- self . send_http ( builder. body ( body) ?) . await . map_err ( Error :: HttpClient ) ?. into_parts ( ) ;
90
- if parts. status . is_success ( ) {
91
- if parts
92
- . headers
93
- . get ( http:: header:: CONTENT_TYPE )
94
- . and_then ( |value| value. to_str ( ) . ok ( ) )
95
- . map_or ( false , |content_type| content_type. starts_with ( "application/json" ) )
96
- {
97
- Ok ( OutputDataOrBytes :: Data ( serde_json:: from_slice ( & body) ?) )
98
- } else {
99
- Ok ( OutputDataOrBytes :: Bytes ( body) )
100
- }
101
- } else {
102
- Err ( Error :: XrpcResponse ( XrpcError {
103
- status : parts. status ,
104
- error : serde_json:: from_slice :: < XrpcErrorKind < E > > ( & body) . ok ( ) ,
105
- } ) )
106
- }
63
+ send_xrpc ( self , request)
64
+ }
65
+ #[ cfg( target_arch = "wasm32" ) ]
66
+ fn send_xrpc < P , I , O , E > (
67
+ & self ,
68
+ request : & XrpcRequest < P , I > ,
69
+ ) -> impl Future < Output = XrpcResult < O , E > >
70
+ where
71
+ P : Serialize + Send + Sync ,
72
+ I : Serialize + Send + Sync ,
73
+ O : DeserializeOwned + Send + Sync ,
74
+ E : DeserializeOwned + Send + Sync + Debug ,
75
+ {
76
+ send_xrpc ( self , request)
77
+ }
78
+ }
79
+
80
+ #[ inline( always) ]
81
+ async fn send_xrpc < P , I , O , E , C : XrpcClient + ?Sized > (
82
+ client : & C ,
83
+ request : & XrpcRequest < P , I > ,
84
+ ) -> XrpcResult < O , E >
85
+ where
86
+ P : Serialize + Send + Sync ,
87
+ I : Serialize + Send + Sync ,
88
+ O : DeserializeOwned + Send + Sync ,
89
+ E : DeserializeOwned + Send + Sync + Debug ,
90
+ {
91
+ let mut uri = format ! ( "{}/xrpc/{}" , client. base_uri( ) , request. nsid) ;
92
+ // Query parameters
93
+ if let Some ( p) = & request. parameters {
94
+ serde_html_form:: to_string ( p) . map ( |qs| {
95
+ uri += "?" ;
96
+ uri += & qs;
97
+ } ) ?;
98
+ } ;
99
+ let mut builder = Request :: builder ( ) . method ( & request. method ) . uri ( & uri) ;
100
+ // Headers
101
+ if let Some ( encoding) = & request. encoding {
102
+ builder = builder. header ( Header :: ContentType , encoding) ;
103
+ }
104
+ if let Some ( token) = client
105
+ . authentication_token (
106
+ request. method == Method :: POST && request. nsid == NSID_REFRESH_SESSION ,
107
+ )
108
+ . await
109
+ {
110
+ builder = builder. header ( Header :: Authorization , format ! ( "Bearer {}" , token) ) ;
111
+ }
112
+ if let Some ( proxy) = client. atproto_proxy_header ( ) . await {
113
+ builder = builder. header ( Header :: AtprotoProxy , proxy) ;
114
+ }
115
+ if let Some ( accept_labelers) = client. atproto_accept_labelers_header ( ) . await {
116
+ builder = builder. header ( Header :: AtprotoAcceptLabelers , accept_labelers. join ( ", " ) ) ;
117
+ }
118
+ // Body
119
+ let body = if let Some ( input) = & request. input {
120
+ match input {
121
+ InputDataOrBytes :: Data ( data) => serde_json:: to_vec ( & data) ?,
122
+ InputDataOrBytes :: Bytes ( bytes) => bytes. clone ( ) ,
123
+ }
124
+ } else {
125
+ Vec :: new ( )
126
+ } ;
127
+ // Send
128
+ let ( parts, body) =
129
+ client. send_http ( builder. body ( body) ?) . await . map_err ( Error :: HttpClient ) ?. into_parts ( ) ;
130
+ if parts. status . is_success ( ) {
131
+ if parts
132
+ . headers
133
+ . get ( http:: header:: CONTENT_TYPE )
134
+ . and_then ( |value| value. to_str ( ) . ok ( ) )
135
+ . map_or ( false , |content_type| content_type. starts_with ( "application/json" ) )
136
+ {
137
+ Ok ( OutputDataOrBytes :: Data ( serde_json:: from_slice ( & body) ?) )
138
+ } else {
139
+ Ok ( OutputDataOrBytes :: Bytes ( body) )
107
140
}
141
+ } else {
142
+ Err ( Error :: XrpcResponse ( XrpcError {
143
+ status : parts. status ,
144
+ error : serde_json:: from_slice :: < XrpcErrorKind < E > > ( & body) . ok ( ) ,
145
+ } ) )
108
146
}
109
147
}
0 commit comments