Skip to content

Commit

Permalink
Relaxing back the Send trait on return types for wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
oestradiol committed Sep 19, 2024
1 parent 06f95bd commit 2400b87
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 58 deletions.
12 changes: 12 additions & 0 deletions atrium-api/src/agent/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,21 @@ pub(crate) use super::Session;

pub trait SessionStore {
#[must_use]
#[cfg(target_arch = "wasm32")]
fn get_session(&self) -> impl Future<Output = Option<Session>>;
#[must_use]
#[cfg(not(target_arch = "wasm32"))]
fn get_session(&self) -> impl Future<Output = Option<Session>> + Send;
#[must_use]
#[cfg(target_arch = "wasm32")]
fn set_session(&self, session: Session) -> impl Future<Output = ()>;
#[must_use]
#[cfg(not(target_arch = "wasm32"))]
fn set_session(&self, session: Session) -> impl Future<Output = ()> + Send;
#[must_use]
#[cfg(target_arch = "wasm32")]
fn clear_session(&self) -> impl Future<Output = ()>;
#[must_use]
#[cfg(not(target_arch = "wasm32"))]
fn clear_session(&self) -> impl Future<Output = ()> + Send;
}
158 changes: 100 additions & 58 deletions atrium-xrpc/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ use std::future::Future;
/// An abstract HTTP client.
pub trait HttpClient {
/// Send an HTTP request and return the response.
#[cfg(target_arch = "wasm32")]
fn send_http(

Check warning on line 14 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
&self,
request: Request<Vec<u8>>,
) -> impl Future<Output = core::result::Result<Response<Vec<u8>>, Box<dyn std::error::Error + Send + Sync + 'static>>>;
#[cfg(not(target_arch = "wasm32"))]
fn send_http(
&self,
request: Request<Vec<u8>>,

Check warning on line 21 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
Expand All @@ -27,18 +33,45 @@ pub trait XrpcClient: HttpClient {
fn base_uri(&self) -> String;
/// Get the authentication token to use `Authorization` header.
#[allow(unused_variables)]
#[cfg(target_arch = "wasm32")]
fn authentication_token(&self, is_refresh: bool) -> impl Future<Output = Option<String>> {
async { None }
}

Check warning on line 39 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
#[allow(unused_variables)]
#[cfg(not(target_arch = "wasm32"))]
fn authentication_token(&self, is_refresh: bool) -> impl Future<Output = Option<String>> + Send {
async { None }
}
/// Get the `atproto-proxy` header.
#[cfg(target_arch = "wasm32")]
fn atproto_proxy_header(&self) -> impl Future<Output = Option<String>> {
async { None }
}
#[cfg(not(target_arch = "wasm32"))]
fn atproto_proxy_header(&self) -> impl Future<Output = Option<String>> + Send {
async { None }
}
/// Get the `atproto-accept-labelers` header.
#[cfg(target_arch = "wasm32")]
fn atproto_accept_labelers_header(&self) -> impl Future<Output = Option<Vec<String>>> {
async { None }
}
#[cfg(not(target_arch = "wasm32"))]
fn atproto_accept_labelers_header(&self) -> impl Future<Output = Option<Vec<String>>> + Send {
async { None }
}

Check warning on line 62 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
/// Send an XRPC request and return the response.
#[cfg(target_arch = "wasm32")]
fn send_xrpc<P, I, O, E>(&self, request: &XrpcRequest<P, I>) -> impl Future<Output = XrpcResult<O, E>>
where
P: Serialize + Send + Sync,
I: Serialize + Send + Sync,
O: DeserializeOwned + Send + Sync,
E: DeserializeOwned + Send + Sync + Debug,
{
send_xrpc(self, request)

Check warning on line 72 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
}
#[cfg(not(target_arch = "wasm32"))]
fn send_xrpc<P, I, O, E>(&self, request: &XrpcRequest<P, I>) -> impl Future<Output = XrpcResult<O, E>> + Send
where
P: Serialize + Send + Sync,
Expand All @@ -47,63 +80,72 @@ pub trait XrpcClient: HttpClient {
E: DeserializeOwned + Send + Sync + Debug,
Self: Sync,
{
async {
let mut uri = format!("{}/xrpc/{}", self.base_uri(), request.nsid);
// Query parameters
if let Some(p) = &request.parameters {
serde_html_form::to_string(p).map(|qs| {
uri += "?";
uri += &qs;
})?;
};
let mut builder = Request::builder().method(&request.method).uri(&uri);
// Headers
if let Some(encoding) = &request.encoding {
builder = builder.header(Header::ContentType, encoding);
}
if let Some(token) = self
.authentication_token(
request.method == Method::POST && request.nsid == NSID_REFRESH_SESSION,
)
.await
{
builder = builder.header(Header::Authorization, format!("Bearer {}", token));
}
if let Some(proxy) = self.atproto_proxy_header().await {
builder = builder.header(Header::AtprotoProxy, proxy);
}
if let Some(accept_labelers) = self.atproto_accept_labelers_header().await {
builder = builder.header(Header::AtprotoAcceptLabelers, accept_labelers.join(", "));
}
// Body
let body = if let Some(input) = &request.input {
match input {
InputDataOrBytes::Data(data) => serde_json::to_vec(&data)?,
InputDataOrBytes::Bytes(bytes) => bytes.clone(),
}
} else {
Vec::new()
};
// Send
let (parts, body) =
self.send_http(builder.body(body)?).await.map_err(Error::HttpClient)?.into_parts();
if parts.status.is_success() {
if parts
.headers
.get(http::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.map_or(false, |content_type| content_type.starts_with("application/json"))
{
Ok(OutputDataOrBytes::Data(serde_json::from_slice(&body)?))
} else {
Ok(OutputDataOrBytes::Bytes(body))
}
} else {
Err(Error::XrpcResponse(XrpcError {
status: parts.status,
error: serde_json::from_slice::<XrpcErrorKind<E>>(&body).ok(),
}))
}
}
send_xrpc(self, request)
}
}

Check warning on line 85 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs

#[inline(always)]
async fn send_xrpc<P, I, O, E, C: XrpcClient + ?Sized>(client: &C, request: &XrpcRequest<P, I>) -> XrpcResult<O, E>
where
P: Serialize + Send + Sync,
I: Serialize + Send + Sync,
O: DeserializeOwned + Send + Sync,
E: DeserializeOwned + Send + Sync + Debug,
{
let mut uri = format!("{}/xrpc/{}", client.base_uri(), request.nsid);
// Query parameters
if let Some(p) = &request.parameters {
serde_html_form::to_string(p).map(|qs| {
uri += "?";
uri += &qs;
})?;
};
let mut builder = Request::builder().method(&request.method).uri(&uri);
// Headers
if let Some(encoding) = &request.encoding {
builder = builder.header(Header::ContentType, encoding);
}
if let Some(token) = client
.authentication_token(
request.method == Method::POST && request.nsid == NSID_REFRESH_SESSION,
)
.await
{
builder = builder.header(Header::Authorization, format!("Bearer {}", token));
}
if let Some(proxy) = client.atproto_proxy_header().await {
builder = builder.header(Header::AtprotoProxy, proxy);
}
if let Some(accept_labelers) = client.atproto_accept_labelers_header().await {
builder = builder.header(Header::AtprotoAcceptLabelers, accept_labelers.join(", "));
}
// Body
let body = if let Some(input) = &request.input {
match input {
InputDataOrBytes::Data(data) => serde_json::to_vec(&data)?,
InputDataOrBytes::Bytes(bytes) => bytes.clone(),
}
} else {
Vec::new()
};
// Send
let (parts, body) =
client.send_http(builder.body(body)?).await.map_err(Error::HttpClient)?.into_parts();
if parts.status.is_success() {
if parts
.headers
.get(http::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.map_or(false, |content_type| content_type.starts_with("application/json"))
{
Ok(OutputDataOrBytes::Data(serde_json::from_slice(&body)?))
} else {
Ok(OutputDataOrBytes::Bytes(body))
}
} else {
Err(Error::XrpcResponse(XrpcError {
status: parts.status,
error: serde_json::from_slice::<XrpcErrorKind<E>>(&body).ok(),
}))

Check warning on line 149 in atrium-xrpc/src/traits.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/atrium-xrpc/src/traits.rs
}
}
19 changes: 19 additions & 0 deletions bsky-sdk/src/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,33 @@ where
T: XrpcClient + Send + Sync,
S: SessionStore + Send + Sync,
{
#[cfg(target_arch = "wasm32")]
fn list(
agent: &BskyAgent<T, S>,
cursor: Option<String>,
limit: Option<LimitedNonZeroU8<100u8>>,
) -> impl Future<Output = Result<list_records::Output>>;
#[cfg(not(target_arch = "wasm32"))]
fn list(
agent: &BskyAgent<T, S>,
cursor: Option<String>,
limit: Option<LimitedNonZeroU8<100u8>>,

Check warning on line 30 in bsky-sdk/src/record.rs

View workflow job for this annotation

GitHub Actions / Rust

Diff in /home/runner/work/atrium/atrium/bsky-sdk/src/record.rs
) -> impl Future<Output = Result<list_records::Output>> + Send;
#[cfg(target_arch = "wasm32")]
fn get(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<get_record::Output>>;
#[cfg(not(target_arch = "wasm32"))]
fn get(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<get_record::Output>> + Send;
#[cfg(target_arch = "wasm32")]
fn put(self, agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<put_record::Output>>;
#[cfg(not(target_arch = "wasm32"))]
fn put(self, agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<put_record::Output>> + Send;
#[cfg(target_arch = "wasm32")]
fn create(self, agent: &BskyAgent<T, S>) -> impl Future<Output = Result<create_record::Output>>;
#[cfg(not(target_arch = "wasm32"))]
fn create(self, agent: &BskyAgent<T, S>) -> impl Future<Output = Result<create_record::Output>> + Send;
#[cfg(target_arch = "wasm32")]
fn delete(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<delete_record::Output>>;
#[cfg(not(target_arch = "wasm32"))]
fn delete(agent: &BskyAgent<T, S>, rkey: String) -> impl Future<Output = Result<delete_record::Output>> + Send;
}

Expand Down

0 comments on commit 2400b87

Please sign in to comment.