fix(sdk): Use a pure HTTP error for methods that don't touch local state

master
Damir Jelić 2021-09-09 10:30:46 +02:00
parent afc8597d3b
commit 6e4a57046e
7 changed files with 65 additions and 34 deletions

View File

@ -145,7 +145,7 @@ use crate::{
verification::{QrVerification, SasVerification, Verification, VerificationRequest},
};
use crate::{
error::HttpError,
error::{HttpError, HttpResult},
event_handler::{EventHandler, EventHandlerData, EventHandlerResult, EventKind, SyncEvent},
http_client::{client_with_config, HttpClient, HttpSend},
room, Error, Result,
@ -645,7 +645,7 @@ impl Client {
Ok(result)
}
async fn discover_homeserver(&self) -> Result<discover_homeserver::Response> {
async fn discover_homeserver(&self) -> HttpResult<discover_homeserver::Response> {
self.send(discover_homeserver::Request::new(), Some(RequestConfig::new().disable_retry()))
.await
}
@ -660,7 +660,7 @@ impl Client {
*homeserver = homeserver_url;
}
async fn get_supported_versions(&self) -> Result<get_supported_versions::Response> {
async fn get_supported_versions(&self) -> HttpResult<get_supported_versions::Response> {
self.send(
get_supported_versions::Request::new(),
Some(RequestConfig::new().disable_retry()),
@ -1123,7 +1123,7 @@ impl Client {
///
/// This should be the first step when trying to login so you can call the
/// appropriate method for the next step.
pub async fn get_login_types(&self) -> Result<get_login_types::Response> {
pub async fn get_login_types(&self) -> HttpResult<get_login_types::Response> {
let request = get_login_types::Request::new();
self.send(request, None).await
}
@ -1540,7 +1540,7 @@ impl Client {
pub async fn register(
&self,
registration: impl Into<register::Request<'_>>,
) -> Result<register::Response> {
) -> HttpResult<register::Response> {
info!("Registering to {}", self.homeserver().await);
let config = if self.appservice_mode {
@ -1630,7 +1630,7 @@ impl Client {
/// # Arguments
///
/// * `room_id` - The `RoomId` of the room to be joined.
pub async fn join_room_by_id(&self, room_id: &RoomId) -> Result<join_room_by_id::Response> {
pub async fn join_room_by_id(&self, room_id: &RoomId) -> HttpResult<join_room_by_id::Response> {
let request = join_room_by_id::Request::new(room_id);
self.send(request, None).await
}
@ -1648,7 +1648,7 @@ impl Client {
&self,
alias: &RoomIdOrAliasId,
server_names: &[Box<ServerName>],
) -> Result<join_room_by_id_or_alias::Response> {
) -> HttpResult<join_room_by_id_or_alias::Response> {
let request = assign!(join_room_by_id_or_alias::Request::new(alias), {
server_name: server_names,
});
@ -1691,7 +1691,7 @@ impl Client {
limit: Option<u32>,
since: Option<&str>,
server: Option<&ServerName>,
) -> Result<get_public_rooms::Response> {
) -> HttpResult<get_public_rooms::Response> {
let limit = limit.map(UInt::from);
let request = assign!(get_public_rooms::Request::new(), {
@ -1732,7 +1732,7 @@ impl Client {
pub async fn create_room(
&self,
room: impl Into<create_room::Request<'_>>,
) -> Result<create_room::Response> {
) -> HttpResult<create_room::Response> {
let request = room.into();
self.send(request, None).await
}
@ -1772,7 +1772,7 @@ impl Client {
pub async fn public_rooms_filtered(
&self,
room_search: impl Into<get_public_rooms_filtered::Request<'_>>,
) -> Result<get_public_rooms_filtered::Response> {
) -> HttpResult<get_public_rooms_filtered::Response> {
let request = room_search.into();
self.send(request, None).await
}
@ -1906,7 +1906,7 @@ impl Client {
let txn_id = txn_id.unwrap_or_else(Uuid::new_v4).to_string();
let request = send_message_event::Request::new(room_id, &txn_id, &content);
self.send(request, None).await
Ok(self.send(request, None).await?)
}
}
@ -1954,7 +1954,7 @@ impl Client {
&self,
request: Request,
config: Option<RequestConfig>,
) -> Result<Request::IncomingResponse>
) -> HttpResult<Request::IncomingResponse>
where
Request: OutgoingRequest + Debug,
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
@ -1966,8 +1966,9 @@ impl Client {
pub(crate) async fn send_to_device(
&self,
request: &ToDeviceRequest,
) -> Result<ToDeviceResponse> {
) -> HttpResult<ToDeviceResponse> {
let txn_id_string = request.txn_id_string();
let request = RumaToDeviceRequest::new_raw(
request.event_type.as_str(),
&txn_id_string,
@ -2000,7 +2001,7 @@ impl Client {
/// }
/// # });
/// ```
pub async fn devices(&self) -> Result<get_devices::Response> {
pub async fn devices(&self) -> HttpResult<get_devices::Response> {
let request = get_devices::Request::new();
self.send(request, None).await
@ -2057,7 +2058,7 @@ impl Client {
&self,
devices: &[DeviceIdBox],
auth_data: Option<AuthData<'_>>,
) -> Result<delete_devices::Response> {
) -> HttpResult<delete_devices::Response> {
let mut request = delete_devices::Request::new(devices);
request.auth = auth_data;
@ -2965,7 +2966,7 @@ impl Client {
}
/// Gets information about the owner of a given access token.
pub async fn whoami(&self) -> Result<whoami::Response> {
pub async fn whoami(&self) -> HttpResult<whoami::Response> {
let request = whoami::Request::new();
self.send(request, None).await
}
@ -3414,12 +3415,8 @@ mod test {
});
if let Err(err) = client.register(user).await {
if let crate::Error::Http(HttpError::UiaaError(FromHttpResponseError::Http(
ServerError::Known(UiaaResponse::MatrixError(client_api::Error {
kind,
message,
status_code,
})),
if let HttpError::UiaaError(FromHttpResponseError::Http(ServerError::Known(
UiaaResponse::MatrixError(client_api::Error { kind, message, status_code }),
))) = err
{
if let client_api::error::ErrorKind::Forbidden = kind {

View File

@ -40,6 +40,9 @@ use url::ParseError as UrlParseError;
/// Result type of the rust-sdk.
pub type Result<T> = std::result::Result<T, Error>;
/// Result type of a pure HTTP request.
pub type HttpResult<T> = std::result::Result<T, HttpError>;
/// An HTTP error, representing either a connection error or an error while
/// converting the raw HTTP response into a Matrix response.
#[derive(Error, Debug)]
@ -182,6 +185,30 @@ pub enum RoomKeyImportError {
Export(#[from] KeyExportError),
}
impl HttpError {
/// Try to destructure the error into an universal interactive auth info.
///
/// Some requests require universal interactive auth, doing such a request
/// will always fail the first time with a 401 status code, the response
/// body will contain info how the client can authenticate.
///
/// The request will need to be retried, this time containing additional
/// authentication data.
///
/// This method is an convenience method to get to the info the server
/// returned on the first, failed request.
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
if let HttpError::UiaaError(FromHttpResponseError::Http(ServerError::Known(
UiaaError::AuthResponse(i),
))) = self
{
Some(i)
} else {
None
}
}
}
impl Error {
/// Try to destructure the error into an universal interactive auth info.
///

View File

@ -107,7 +107,7 @@ pub use client::{Client, ClientConfig, LoopCtrl, RequestConfig, SyncSettings};
#[cfg(feature = "encryption")]
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
pub use device::Device;
pub use error::{Error, HttpError, Result};
pub use error::{Error, HttpError, HttpResult, Result};
pub use http_client::HttpSend;
pub use room_member::RoomMember;
#[cfg(not(target_arch = "wasm32"))]

View File

@ -14,6 +14,7 @@ use ruma::{
};
use crate::{
error::HttpResult,
media::{MediaFormat, MediaRequest, MediaType},
room::RoomType,
BaseRoom, Client, Result, RoomMember,
@ -143,7 +144,7 @@ impl Common {
pub async fn messages(
&self,
request: impl Into<get_message_events::Request<'_>>,
) -> Result<get_message_events::Response> {
) -> HttpResult<get_message_events::Response> {
let request = request.into();
self.client.send(request, None).await
}

View File

@ -46,7 +46,7 @@ use ruma::{
#[cfg(feature = "encryption")]
use tracing::instrument;
use crate::{room::Common, BaseRoom, Client, Error, Result, RoomType};
use crate::{error::HttpResult, room::Common, BaseRoom, Client, HttpError, Result, RoomType};
const TYPING_NOTICE_TIMEOUT: Duration = Duration::from_secs(4);
const TYPING_NOTICE_RESEND_TIMEOUT: Duration = Duration::from_secs(3);
@ -562,7 +562,7 @@ impl Joined {
&self,
content: impl Into<AnyStateEventContent>,
state_key: &str,
) -> Result<send_state_event::Response> {
) -> HttpResult<send_state_event::Response> {
let content = content.into();
let request = send_state_event::Request::new(self.inner.room_id(), state_key, &content);
@ -606,7 +606,7 @@ impl Joined {
event_id: &EventId,
reason: Option<&str>,
txn_id: Option<Uuid>,
) -> Result<redact_event::Response> {
) -> HttpResult<redact_event::Response> {
let txn_id = txn_id.unwrap_or_else(Uuid::new_v4).to_string();
let request =
assign!(redact_event::Request::new(self.inner.room_id(), event_id, &txn_id), {
@ -642,8 +642,8 @@ impl Joined {
/// room.set_tag("u.work", tag_info );
/// # })
/// ```
pub async fn set_tag(&self, tag: &str, tag_info: TagInfo) -> Result<create_tag::Response> {
let user_id = self.client.user_id().await.ok_or(Error::AuthenticationRequired)?;
pub async fn set_tag(&self, tag: &str, tag_info: TagInfo) -> HttpResult<create_tag::Response> {
let user_id = self.client.user_id().await.ok_or(HttpError::AuthenticationRequired)?;
let request = create_tag::Request::new(&user_id, self.inner.room_id(), tag, tag_info);
self.client.send(request, None).await
}
@ -654,8 +654,8 @@ impl Joined {
///
/// # Arguments
/// * `tag` - The tag to remove.
pub async fn remove_tag(&self, tag: &str) -> Result<delete_tag::Response> {
let user_id = self.client.user_id().await.ok_or(Error::AuthenticationRequired)?;
pub async fn remove_tag(&self, tag: &str) -> HttpResult<delete_tag::Response> {
let user_id = self.client.user_id().await.ok_or(HttpError::AuthenticationRequired)?;
let request = delete_tag::Request::new(&user_id, self.inner.room_id(), tag);
self.client.send(request, None).await
}

View File

@ -87,3 +87,9 @@ impl From<warp::Rejection> for Error {
Self::WarpRejection(format!("{:?}", rejection))
}
}
impl From<matrix_sdk::HttpError> for Error {
fn from(e: matrix_sdk::HttpError) -> Self {
matrix_sdk::Error::from(e).into()
}
}

View File

@ -94,7 +94,7 @@ use matrix_sdk::{
bytes::Bytes,
event_handler::{EventHandler, EventHandlerResult, SyncEvent},
reqwest::Url,
Client, ClientConfig, HttpError, Session,
Client, ClientConfig, Session,
};
use regex::Regex;
use ruma::{
@ -402,9 +402,9 @@ impl AppService {
match client.register(request).await {
Ok(_) => (),
Err(error) => match error {
matrix_sdk::Error::Http(HttpError::UiaaError(FromHttpResponseError::Http(
matrix_sdk::HttpError::UiaaError(FromHttpResponseError::Http(
ServerError::Known(UiaaResponse::MatrixError(ref matrix_error)),
))) => {
)) => {
match matrix_error.kind {
ErrorKind::UserInUse => {
// TODO: persist the fact that we registered that user