Skip to content

Commit aea4389

Browse files
committed
Relaxing back the Send trait on return types for wasm
1 parent 078241f commit aea4389

File tree

3 files changed

+131
-58
lines changed

3 files changed

+131
-58
lines changed

atrium-api/src/agent/store.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,21 @@ pub(crate) use super::Session;
77

88
pub trait SessionStore {
99
#[must_use]
10+
#[cfg(target_arch = "wasm32")]
11+
fn get_session(&self) -> impl Future<Output = Option<Session>>;
12+
#[must_use]
13+
#[cfg(not(target_arch = "wasm32"))]
1014
fn get_session(&self) -> impl Future<Output = Option<Session>> + Send;
1115
#[must_use]
16+
#[cfg(target_arch = "wasm32")]
17+
fn set_session(&self, session: Session) -> impl Future<Output = ()>;
18+
#[must_use]
19+
#[cfg(not(target_arch = "wasm32"))]
1220
fn set_session(&self, session: Session) -> impl Future<Output = ()> + Send;
1321
#[must_use]
22+
#[cfg(target_arch = "wasm32")]
23+
fn clear_session(&self) -> impl Future<Output = ()>;
24+
#[must_use]
25+
#[cfg(not(target_arch = "wasm32"))]
1426
fn clear_session(&self) -> impl Future<Output = ()> + Send;
1527
}

atrium-xrpc/src/traits.rs

Lines changed: 100 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ use std::future::Future;
1010
/// An abstract HTTP client.
1111
pub trait HttpClient {
1212
/// Send an HTTP request and return the response.
13+
#[cfg(target_arch = "wasm32")]
14+
fn send_http(
15+
&self,
16+
request: Request<Vec<u8>>,
17+
) -> impl Future<Output = core::result::Result<Response<Vec<u8>>, Box<dyn std::error::Error + Send + Sync + 'static>>>;
18+
#[cfg(not(target_arch = "wasm32"))]
1319
fn send_http(
1420
&self,
1521
request: Request<Vec<u8>>,
@@ -27,18 +33,45 @@ pub trait XrpcClient: HttpClient {
2733
fn base_uri(&self) -> String;
2834
/// Get the authentication token to use `Authorization` header.
2935
#[allow(unused_variables)]
36+
#[cfg(target_arch = "wasm32")]
37+
fn authentication_token(&self, is_refresh: bool) -> impl Future<Output = Option<String>> {
38+
async { None }
39+
}
40+
#[allow(unused_variables)]
41+
#[cfg(not(target_arch = "wasm32"))]
3042
fn authentication_token(&self, is_refresh: bool) -> impl Future<Output = Option<String>> + Send {
3143
async { None }
3244
}
3345
/// Get the `atproto-proxy` header.
46+
#[cfg(target_arch = "wasm32")]
47+
fn atproto_proxy_header(&self) -> impl Future<Output = Option<String>> {
48+
async { None }
49+
}
50+
#[cfg(not(target_arch = "wasm32"))]
3451
fn atproto_proxy_header(&self) -> impl Future<Output = Option<String>> + Send {
3552
async { None }
3653
}
3754
/// Get the `atproto-accept-labelers` header.
55+
#[cfg(target_arch = "wasm32")]
56+
fn atproto_accept_labelers_header(&self) -> impl Future<Output = Option<Vec<String>>> {
57+
async { None }
58+
}
59+
#[cfg(not(target_arch = "wasm32"))]
3860
fn atproto_accept_labelers_header(&self) -> impl Future<Output = Option<Vec<String>>> + Send {
3961
async { None }
4062
}
4163
/// Send an XRPC request and return the response.
64+
#[cfg(target_arch = "wasm32")]
65+
fn send_xrpc<P, I, O, E>(&self, request: &XrpcRequest<P, I>) -> impl Future<Output = XrpcResult<O, E>>
66+
where
67+
P: Serialize + Send + Sync,
68+
I: Serialize + Send + Sync,
69+
O: DeserializeOwned + Send + Sync,
70+
E: DeserializeOwned + Send + Sync + Debug,
71+
{
72+
send_xrpc(self, request)
73+
}
74+
#[cfg(not(target_arch = "wasm32"))]
4275
fn send_xrpc<P, I, O, E>(&self, request: &XrpcRequest<P, I>) -> impl Future<Output = XrpcResult<O, E>> + Send
4376
where
4477
P: Serialize + Send + Sync,
@@ -47,63 +80,72 @@ pub trait XrpcClient: HttpClient {
4780
E: DeserializeOwned + Send + Sync + Debug,
4881
Self: Sync,
4982
{
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-
}
107-
}
83+
send_xrpc(self, request)
10884
}
10985
}
86+
87+
#[inline(always)]
88+
async fn send_xrpc<P, I, O, E, C: XrpcClient + ?Sized>(client: &C, request: &XrpcRequest<P, I>) -> XrpcResult<O, E>
89+
where
90+
P: Serialize + Send + Sync,
91+
I: Serialize + Send + Sync,
92+
O: DeserializeOwned + Send + Sync,
93+
E: DeserializeOwned + Send + Sync + Debug,
94+
{
95+
let mut uri = format!("{}/xrpc/{}", client.base_uri(), request.nsid);
96+
// Query parameters
97+
if let Some(p) = &request.parameters {
98+
serde_html_form::to_string(p).map(|qs| {
99+
uri += "?";
100+
uri += &qs;
101+
})?;
102+
};
103+
let mut builder = Request::builder().method(&request.method).uri(&uri);
104+
// Headers
105+
if let Some(encoding) = &request.encoding {
106+
builder = builder.header(Header::ContentType, encoding);
107+
}
108+
if let Some(token) = client
109+
.authentication_token(
110+
request.method == Method::POST && request.nsid == NSID_REFRESH_SESSION,
111+
)
112+
.await
113+
{
114+
builder = builder.header(Header::Authorization, format!("Bearer {}", token));
115+
}
116+
if let Some(proxy) = client.atproto_proxy_header().await {
117+
builder = builder.header(Header::AtprotoProxy, proxy);
118+
}
119+
if let Some(accept_labelers) = client.atproto_accept_labelers_header().await {
120+
builder = builder.header(Header::AtprotoAcceptLabelers, accept_labelers.join(", "));
121+
}
122+
// Body
123+
let body = if let Some(input) = &request.input {
124+
match input {
125+
InputDataOrBytes::Data(data) => serde_json::to_vec(&data)?,
126+
InputDataOrBytes::Bytes(bytes) => bytes.clone(),
127+
}
128+
} else {
129+
Vec::new()
130+
};
131+
// Send
132+
let (parts, body) =
133+
client.send_http(builder.body(body)?).await.map_err(Error::HttpClient)?.into_parts();
134+
if parts.status.is_success() {
135+
if parts
136+
.headers
137+
.get(http::header::CONTENT_TYPE)
138+
.and_then(|value| value.to_str().ok())
139+
.map_or(false, |content_type| content_type.starts_with("application/json"))
140+
{
141+
Ok(OutputDataOrBytes::Data(serde_json::from_slice(&body)?))
142+
} else {
143+
Ok(OutputDataOrBytes::Bytes(body))
144+
}
145+
} else {
146+
Err(Error::XrpcResponse(XrpcError {
147+
status: parts.status,
148+
error: serde_json::from_slice::<XrpcErrorKind<E>>(&body).ok(),
149+
}))
150+
}
151+
}

bsky-sdk/src/record.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,33 @@ where
1717
T: XrpcClient + Send + Sync,
1818
S: SessionStore + Send + Sync,
1919
{
20+
#[cfg(target_arch = "wasm32")]
21+
fn list(
22+
agent: &BskyAgent<T, S>,
23+
cursor: Option<String>,
24+
limit: Option<LimitedNonZeroU8<100u8>>,
25+
) -> impl Future<Output = Result<list_records::Output>>;
26+
#[cfg(not(target_arch = "wasm32"))]
2027
fn list(
2128
agent: &BskyAgent<T, S>,
2229
cursor: Option<String>,
2330
limit: Option<LimitedNonZeroU8<100u8>>,
2431
) -> impl Future<Output = Result<list_records::Output>> + Send;
32+
#[cfg(target_arch = "wasm32")]
33+
fn get(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<get_record::Output>>;
34+
#[cfg(not(target_arch = "wasm32"))]
2535
fn get(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<get_record::Output>> + Send;
36+
#[cfg(target_arch = "wasm32")]
37+
fn put(self, agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<put_record::Output>>;
38+
#[cfg(not(target_arch = "wasm32"))]
2639
fn put(self, agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<put_record::Output>> + Send;
40+
#[cfg(target_arch = "wasm32")]
41+
fn create(self, agent: &BskyAgent<T, S>) -> impl Future<Output = Result<create_record::Output>>;
42+
#[cfg(not(target_arch = "wasm32"))]
2743
fn create(self, agent: &BskyAgent<T, S>) -> impl Future<Output = Result<create_record::Output>> + Send;
44+
#[cfg(target_arch = "wasm32")]
45+
fn delete(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<delete_record::Output>>;
46+
#[cfg(not(target_arch = "wasm32"))]
2847
fn delete(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<delete_record::Output>> + Send;
2948
}
3049

0 commit comments

Comments
 (0)