Skip to content

Commit

Permalink
feat: event handlers for client API (#29)
Browse files Browse the repository at this point in the history
This also adds the Mxc and Filter API as well as deprecate our `UserId`
in favor of `ruma`'s.

<!--
Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->
  • Loading branch information
avdb13 authored Feb 17, 2024
1 parent a38a1fd commit 2da3045
Show file tree
Hide file tree
Showing 25 changed files with 1,279 additions and 466 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ resolver = "1"
[workspace.dependencies]
anyhow = "1.0.75"
axum = { version = "0.7.4", features = ["tokio"] }
chrono = { version = "0.4.34", features = ["serde"] }
dotenv = "0.15.0"
http = "0.2.11"
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "stream", "multipart"] }
mime = "0.3.17"
openssl = { version = "0.10.63", features = ["vendored"] }
openssl-sys = { version = "0.9.99", features = ["vendored"] }
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "multipart"] }
serde = "1.0.192"
serde_json = "1.0.108"
tokio = "1.34.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
tracing-subscriber = { version = "0.3.18", features = ["json"] }
uuid = { version = "1.6.1", features = ["v4"] }
url = "2.4.1"
4 changes: 2 additions & 2 deletions crates/core/src/account/model.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use url::Url;

use matrix::admin::resources::user_id::UserId;
use matrix::ruma_common::OwnedUserId;

#[derive(Debug, Clone)]
pub struct Account {
pub user_id: UserId,
pub user_id: OwnedUserId,
pub username: String,
pub email: String,
pub display_name: String,
Expand Down
37 changes: 24 additions & 13 deletions crates/core/src/account/service.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::sync::Arc;

use matrix::{admin::resources::user::UserService, client::resources::session::Session};
use matrix::{
admin::resources::user::UserService, client::resources::session::Session, ruma_common::UserId,
};
use tracing::instrument;
use url::Url;
use uuid::Uuid;
use validator::{Validate, ValidationError};

use matrix::{
admin::resources::{
user::{CreateUserBody, ListUsersQuery, LoginAsUserBody, ThreePid},
user_id::UserId,
},
admin::resources::user::{CreateUserBody, ListUsersQuery, LoginAsUserBody, ThreePid},
Client as MatrixAdminClient,
};

Expand Down Expand Up @@ -117,7 +116,13 @@ impl AccountService {
/// Returs `true` if the given `email address` is NOT registered in the
/// Matrix Server
pub async fn is_email_available(&self, email: &str) -> Result<bool> {
let user_id = UserId::new(email, self.admin.server_name());
let user_id = format!("@{}:{}", email, self.admin.server_name());
let user_id = <&UserId>::try_from(user_id.as_str()).map_err(|err| {
// TODO
tracing::error!(?err, "Failed to parse username");
Error::Unknown
})?;

let exists = UserService::list(
&self.admin,
ListUsersQuery {
Expand Down Expand Up @@ -206,15 +211,21 @@ impl AccountService {
return Err(AccountErrorCode::EmailTaken(dto.email).into());
}

let user_id = UserId::new(dto.username.clone(), self.admin.server_name().to_string());
let user_id = format!("@{}:{}", dto.username, self.admin.server_name());
let user_id = <&UserId>::try_from(user_id.as_str()).map_err(|err| {
// TODO
tracing::error!(?err, "Failed to parse username");
Error::Unknown
})?;

let avatar_url = Url::parse(DEFAULT_AVATAR_URL).map_err(|err| {
tracing::error!(?err, "Failed to parse default avatar url");
Error::Unknown
})?;

UserService::create(
&self.admin,
user_id.clone(),
user_id,
CreateUserBody {
displayname: Some(dto.username),
password: dto.password.to_string(),
Expand All @@ -239,14 +250,14 @@ impl AccountService {
Error::Unknown
})?;

let matrix_account = UserService::query_user_account(&self.admin, user_id.clone())
let matrix_account = UserService::query_user_account(&self.admin, user_id)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to query user account");
Error::Unknown
})?;
let account = Account {
user_id,
user_id: user_id.into(),
username: matrix_account.name,
email: matrix_account
.threepids
Expand All @@ -264,9 +275,9 @@ impl AccountService {
}

/// Creates an access token for the given user
pub async fn issue_user_token(&self, user_id: UserId) -> Result<String> {
pub async fn issue_user_token(&self, user_id: &UserId) -> Result<String> {
let credentials =
UserService::login_as_user(&self.admin, user_id.clone(), LoginAsUserBody::default())
UserService::login_as_user(&self.admin, user_id, LoginAsUserBody::default())
.await
.map_err(|err| {
tracing::error!(?err, ?user_id, "Failed to login as user");
Expand All @@ -283,7 +294,7 @@ impl AccountService {
tracing::error!(?err, "Failed to get session from matrix as client");
Error::Unknown
})?;
let matrix_account = UserService::query_user_account(&self.admin, session.user_id.clone())
let matrix_account = UserService::query_user_account(&self.admin, &session.user_id)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to query user account");
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/room/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tracing::instrument;

use matrix::{
client::resources::room::{
CreateRoomBody, Room as MatrixRoom, RoomCreationContent, RoomPreset,
CreateRoomBody, RoomCreationContent, RoomPreset, RoomService as MatrixRoomService,
},
Client as MatrixAdminClient,
};
Expand Down Expand Up @@ -36,7 +36,7 @@ impl RoomService {
access_token: &Secret,
dto: CreateRoomDto,
) -> Result<Room> {
match MatrixRoom::create(
match MatrixRoomService::create(
&self.admin,
access_token.to_string(),
CreateRoomBody {
Expand Down
3 changes: 3 additions & 0 deletions crates/matrix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ ruma-macros = "0.12.0"

# Workspace Dependencies
anyhow = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
mime = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
serde = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
4 changes: 2 additions & 2 deletions crates/matrix/src/admin/resources/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ruma_events::{AnyMessageLikeEvent, AnyStateEvent, AnyTimelineEvent};
use serde::{Deserialize, Serialize};
use tracing::instrument;

use crate::{error::MatrixError, event_filter::RoomEventFilter, http::Client};
use crate::{error::MatrixError, filter::RoomEventFilter, http::Client};

#[derive(Default)]
pub struct RoomService;
Expand Down Expand Up @@ -444,7 +444,7 @@ impl RoomService {
}
}

#[derive(Default, Debug, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub enum Direction {
#[serde(rename = "f")]
#[default]
Expand Down
11 changes: 5 additions & 6 deletions crates/matrix/src/admin/resources/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
//! for a server admin: see Admin API.
use anyhow::Result;
use ruma_common::UserId;
use serde::{Deserialize, Serialize};
use tracing::instrument;
use url::Url;

use crate::{error::MatrixError, http::Client};

use super::user_id::UserId;

#[derive(Default)]
pub struct UserService;

Expand Down Expand Up @@ -149,7 +148,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/v1.88/admin_api/user_admin_api.html#query-user-account
#[instrument(skip(client))]
pub async fn query_user_account(client: &Client, user_id: UserId) -> Result<User> {
pub async fn query_user_account(client: &Client, user_id: &UserId) -> Result<User> {
let resp = client
.get(format!(
"/_synapse/admin/v2/users/{user_id}",
Expand All @@ -174,7 +173,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#create-or-modify-account
#[instrument(skip(client, body))]
pub async fn create(client: &Client, user_id: UserId, body: CreateUserBody) -> Result<User> {
pub async fn create(client: &Client, user_id: &UserId, body: CreateUserBody) -> Result<User> {
let resp = client
.put_json(
format!("/_synapse/admin/v2/users/{user_id}", user_id = user_id),
Expand Down Expand Up @@ -212,7 +211,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#create-or-modify-account
#[instrument(skip(client))]
pub async fn update(client: &Client, user_id: UserId, body: UpdateUserBody) -> Result<User> {
pub async fn update(client: &Client, user_id: &UserId, body: UpdateUserBody) -> Result<User> {
let resp = client
.put_json(
format!("/_synapse/admin/v2/users/{user_id}", user_id = user_id),
Expand Down Expand Up @@ -246,7 +245,7 @@ impl UserService {
#[instrument(skip(client))]
pub async fn login_as_user(
client: &Client,
user_id: UserId,
user_id: &UserId,
body: LoginAsUserBody,
) -> Result<LoginAsUserResponse> {
let resp = client
Expand Down
73 changes: 54 additions & 19 deletions crates/matrix/src/client/resources/events.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use ruma_common::{serde::Raw, EventId, OwnedEventId, RoomId, TransactionId};
use ruma_common::{serde::Raw, EventId, OwnedEventId, OwnedTransactionId, RoomId};

use ruma_events::{
relation::RelationType, AnyMessageLikeEvent, AnyStateEvent, AnyStateEventContent,
Expand All @@ -9,25 +9,39 @@ use ruma_events::{
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tracing::instrument;

use crate::{admin::resources::room::Direction, event_filter::RoomEventFilter, Client};
use crate::{admin::resources::room::Direction, error::MatrixError, Client};

pub struct Events;
pub struct EventsService;

#[derive(Debug, Default, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub struct GetMessagesQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
pub dir: Option<Direction>,
pub filter: Option<RoomEventFilter>,

pub dir: Direction,

#[serde(skip_serializing_if = "String::is_empty")]
pub filter: String,
}

#[derive(Debug, Default, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub struct GetRelationsQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
pub dir: Option<Direction>,

pub dir: Direction,
}

#[derive(Debug, Deserialize)]
Expand All @@ -40,7 +54,7 @@ pub struct GetMessagesResponse {

#[derive(Debug, Deserialize)]
#[serde(transparent)]
pub struct GetStateResponse(Vec<Raw<AnyStateEvent>>);
pub struct GetStateResponse(pub Vec<Raw<AnyStateEvent>>);

#[derive(Debug, Deserialize)]
pub struct GetRelationsResponse {
Expand Down Expand Up @@ -70,7 +84,7 @@ pub struct SendRedactionResponse {
pub event_id: OwnedEventId,
}

impl Events {
impl EventsService {
#[instrument(skip(client, access_token))]
pub async fn get_event(
client: &Client,
Expand Down Expand Up @@ -103,10 +117,13 @@ impl Events {
tmp.set_token(access_token)?;

let resp = tmp
.get(format!(
"/_matrix/client/v3/rooms/{room_id}/messages",
room_id = room_id,
))
.get_query(
format!(
"/_matrix/client/v3/rooms/{room_id}/messages",
room_id = room_id,
),
&query,
)
.await?;

Ok(resp.json().await?)
Expand Down Expand Up @@ -199,7 +216,7 @@ impl Events {
client: &Client,
access_token: impl Into<String>,
room_id: &RoomId,
txn_id: &TransactionId,
txn_id: OwnedTransactionId,
body: T,
) -> Result<SendMessageResponse> {
let mut tmp = (*client).clone();
Expand All @@ -217,7 +234,13 @@ impl Events {
)
.await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}

#[instrument(skip(client, access_token, body))]
Expand All @@ -243,7 +266,13 @@ impl Events {

let resp = tmp.put_json(path, &body).await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}

#[instrument(skip(client, access_token, body))]
Expand All @@ -252,7 +281,7 @@ impl Events {
access_token: impl Into<String>,
room_id: &RoomId,
event_id: &EventId,
txn_id: &TransactionId,
txn_id: OwnedTransactionId,
body: SendRedactionBody,
) -> Result<SendRedactionResponse> {
let mut tmp = (*client).clone();
Expand All @@ -270,6 +299,12 @@ impl Events {
)
.await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}
}
1 change: 1 addition & 0 deletions crates/matrix/src/client/resources/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod error;
pub mod events;
pub mod login;
pub mod mxc;
pub mod room;
pub mod session;
Loading

0 comments on commit 2da3045

Please sign in to comment.