mas_matrix_synapse/
error.rs

1// Copyright 2024 New Vector Ltd.
2//
3// SPDX-License-Identifier: AGPL-3.0-only
4// Please see LICENSE in the repository root for full details.
5
6use std::fmt::Display;
7
8use async_trait::async_trait;
9use serde::Deserialize;
10use thiserror::Error;
11
12/// Represents a Matrix error
13/// Ref: <https://spec.matrix.org/v1.10/client-server-api/#standard-error-response>
14#[derive(Debug, Deserialize)]
15struct MatrixError {
16    errcode: String,
17    error: String,
18}
19
20/// Represents an error received from the homeserver.
21/// Where possible, we capture the Matrix error from the JSON response body.
22#[derive(Debug, Error)]
23pub(crate) struct Error {
24    synapse_error: Option<MatrixError>,
25
26    #[source]
27    source: reqwest::Error,
28}
29
30impl Display for Error {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        if let Some(matrix_error) = &self.synapse_error {
33            write!(f, "{}: {}", matrix_error.errcode, matrix_error.error)
34        } else {
35            write!(f, "(no specific error)")
36        }
37    }
38}
39
40impl Error {
41    /// Return the error code (`errcode`)
42    pub fn errcode(&self) -> Option<&str> {
43        let me = self.synapse_error.as_ref()?;
44        Some(&me.errcode)
45    }
46}
47
48/// An extension trait for [`reqwest::Response`] to help working with errors
49/// from Synapse.
50#[async_trait]
51pub(crate) trait SynapseResponseExt: Sized {
52    async fn error_for_synapse_error(self) -> Result<Self, Error>;
53}
54
55#[async_trait]
56impl SynapseResponseExt for reqwest::Response {
57    async fn error_for_synapse_error(self) -> Result<Self, Error> {
58        match self.error_for_status_ref() {
59            Ok(_response) => Ok(self),
60            Err(source) => {
61                let synapse_error = self.json().await.ok();
62                Err(Error {
63                    synapse_error,
64                    source,
65                })
66            }
67        }
68    }
69}