1
1
#![ doc = include_str ! ( "../README.md" ) ]
2
2
pub mod error;
3
+ mod traits;
4
+ mod types;
3
5
4
- use crate :: error:: { Error , XrpcError , XrpcErrorKind } ;
5
- use async_trait:: async_trait;
6
- use http:: { Method , Request , Response } ;
7
- use serde:: { de:: DeserializeOwned , Serialize } ;
8
-
9
- /// A type which can be used as a parameter of [`XrpcRequest`].
10
- ///
11
- /// JSON serializable data or raw bytes.
12
- pub enum InputDataOrBytes < T >
13
- where
14
- T : Serialize ,
15
- {
16
- Data ( T ) ,
17
- Bytes ( Vec < u8 > ) ,
18
- }
19
-
20
- /// A type which can be used as a return value of [`XrpcClient::send_xrpc()`].
21
- ///
22
- /// JSON deserializable data or raw bytes.
23
- pub enum OutputDataOrBytes < T >
24
- where
25
- T : DeserializeOwned ,
26
- {
27
- Data ( T ) ,
28
- Bytes ( Vec < u8 > ) ,
29
- }
30
-
31
- /// An abstract HTTP client.
32
- #[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
33
- #[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
34
- pub trait HttpClient {
35
- async fn send_http (
36
- & self ,
37
- request : Request < Vec < u8 > > ,
38
- ) -> Result < Response < Vec < u8 > > , Box < dyn std:: error:: Error + Send + Sync + ' static > > ;
39
- }
40
-
41
- /// A request which can be executed with [`XrpcClient::send_xrpc()`].
42
- pub struct XrpcRequest < P , I >
43
- where
44
- I : Serialize ,
45
- {
46
- pub method : Method ,
47
- pub path : String ,
48
- pub parameters : Option < P > ,
49
- pub input : Option < InputDataOrBytes < I > > ,
50
- pub encoding : Option < String > ,
51
- }
52
-
53
- pub type XrpcResult < O , E > = Result < OutputDataOrBytes < O > , self :: Error < E > > ;
54
-
55
- /// An abstract XRPC client.
56
- ///
57
- /// [`send_xrpc()`](XrpcClient::send_xrpc) method has a default implementation,
58
- /// which wraps the [`HttpClient::send_http()`]` method to handle input and output as an XRPC Request.
59
- #[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
60
- #[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
61
- pub trait XrpcClient : HttpClient {
62
- fn base_uri ( & self ) -> String ;
63
- #[ allow( unused_variables) ]
64
- async fn auth ( & self , is_refresh : bool ) -> Option < String > {
65
- None
66
- }
67
- async fn send_xrpc < P , I , O , E > ( & self , request : & XrpcRequest < P , I > ) -> XrpcResult < O , E >
68
- where
69
- P : Serialize + Send + Sync ,
70
- I : Serialize + Send + Sync ,
71
- O : DeserializeOwned + Send + Sync ,
72
- E : DeserializeOwned + Send + Sync ,
73
- {
74
- let mut uri = format ! ( "{}/xrpc/{}" , self . base_uri( ) , request. path) ;
75
- if let Some ( p) = & request. parameters {
76
- serde_html_form:: to_string ( p) . map ( |qs| {
77
- uri += "?" ;
78
- uri += & qs;
79
- } ) ?;
80
- } ;
81
- let mut builder = Request :: builder ( ) . method ( & request. method ) . uri ( & uri) ;
82
- if let Some ( encoding) = & request. encoding {
83
- builder = builder. header ( http:: header:: CONTENT_TYPE , encoding) ;
84
- }
85
- if let Some ( token) = self
86
- . auth (
87
- request. method == Method :: POST
88
- && request. path == "com.atproto.server.refreshSession" ,
89
- )
90
- . await
91
- {
92
- builder = builder. header ( http:: header:: AUTHORIZATION , format ! ( "Bearer {}" , token) ) ;
93
- }
94
- let body = if let Some ( input) = & request. input {
95
- match input {
96
- InputDataOrBytes :: Data ( data) => serde_json:: to_vec ( & data) ?,
97
- InputDataOrBytes :: Bytes ( bytes) => bytes. clone ( ) ,
98
- }
99
- } else {
100
- Vec :: new ( )
101
- } ;
102
- let ( parts, body) = self
103
- . send_http ( builder. body ( body) ?)
104
- . await
105
- . map_err ( Error :: HttpClient ) ?
106
- . into_parts ( ) ;
107
- if parts. status . is_success ( ) {
108
- if parts
109
- . headers
110
- . get ( http:: header:: CONTENT_TYPE )
111
- . and_then ( |value| value. to_str ( ) . ok ( ) )
112
- . map_or ( false , |content_type| {
113
- content_type. starts_with ( "application/json" )
114
- } )
115
- {
116
- Ok ( OutputDataOrBytes :: Data ( serde_json:: from_slice ( & body) ?) )
117
- } else {
118
- Ok ( OutputDataOrBytes :: Bytes ( body) )
119
- }
120
- } else {
121
- Err ( Error :: XrpcResponse ( XrpcError {
122
- status : parts. status ,
123
- error : serde_json:: from_slice :: < XrpcErrorKind < E > > ( & body) . ok ( ) ,
124
- } ) )
125
- }
126
- }
127
- }
6
+ pub use crate :: error:: { Error , Result } ;
7
+ pub use crate :: traits:: { HttpClient , XrpcClient } ;
8
+ pub use crate :: types:: { InputDataOrBytes , OutputDataOrBytes , XrpcRequest } ;
128
9
129
10
#[ cfg( test) ]
130
11
mod tests {
131
12
use super :: * ;
13
+ use crate :: error:: { XrpcError , XrpcErrorKind } ;
14
+ use crate :: { HttpClient , XrpcClient } ;
15
+ use async_trait:: async_trait;
16
+ use http:: { Request , Response } ;
132
17
#[ cfg( target_arch = "wasm32" ) ]
133
18
use wasm_bindgen_test:: * ;
134
19
@@ -144,7 +29,10 @@ mod tests {
144
29
async fn send_http (
145
30
& self ,
146
31
_request : Request < Vec < u8 > > ,
147
- ) -> Result < Response < Vec < u8 > > , Box < dyn std:: error:: Error + Send + Sync + ' static > > {
32
+ ) -> core:: result:: Result <
33
+ Response < Vec < u8 > > ,
34
+ Box < dyn std:: error:: Error + Send + Sync + ' static > ,
35
+ > {
148
36
let mut builder = Response :: builder ( ) . status ( self . status ) ;
149
37
if self . json {
150
38
builder = builder. header ( http:: header:: CONTENT_TYPE , "application/json" )
@@ -162,7 +50,7 @@ mod tests {
162
50
mod errors {
163
51
use super :: * ;
164
52
165
- async fn get_example < T > ( xrpc : & T , params : Parameters ) -> Result < Output , crate :: Error < Error > >
53
+ async fn get_example < T > ( xrpc : & T , params : Parameters ) -> Result < Output , Error >
166
54
where
167
55
T : crate :: XrpcClient + Send + Sync ,
168
56
{
@@ -305,10 +193,7 @@ mod tests {
305
193
mod bytes {
306
194
use super :: * ;
307
195
308
- async fn get_bytes < T > (
309
- xrpc : & T ,
310
- params : Parameters ,
311
- ) -> Result < Vec < u8 > , crate :: Error < Error > >
196
+ async fn get_bytes < T > ( xrpc : & T , params : Parameters ) -> Result < Vec < u8 > , Error >
312
197
where
313
198
T : crate :: XrpcClient + Send + Sync ,
314
199
{
@@ -387,7 +272,7 @@ mod tests {
387
272
mod no_content {
388
273
use super :: * ;
389
274
390
- async fn create_data < T > ( xrpc : & T , input : Input ) -> Result < ( ) , crate :: Error < Error > >
275
+ async fn create_data < T > ( xrpc : & T , input : Input ) -> Result < ( ) , Error >
391
276
where
392
277
T : crate :: XrpcClient + Send + Sync ,
393
278
{
@@ -449,7 +334,7 @@ mod tests {
449
334
mod bytes {
450
335
use super :: * ;
451
336
452
- async fn create_data < T > ( xrpc : & T , input : Vec < u8 > ) -> Result < Output , crate :: Error < Error > >
337
+ async fn create_data < T > ( xrpc : & T , input : Vec < u8 > ) -> Result < Output , Error >
453
338
where
454
339
T : crate :: XrpcClient + Send + Sync ,
455
340
{
0 commit comments