From 093588d5a3095ae200b56bec921156febee7cd95 Mon Sep 17 00:00:00 2001 From: Amanda Graven Date: Mon, 4 Oct 2021 11:49:13 +0200 Subject: [PATCH] Event handlers for room and user queries Add a member to AppService which can store closures that will be invoked when the homeserver invokes query endpoints. --- .../src/event_handler.rs | 35 +++++++++++++++++ crates/matrix-sdk-appservice/src/lib.rs | 34 +++++++++++++++- .../src/webserver/warp.rs | 39 ++++++++++++++++--- 3 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 crates/matrix-sdk-appservice/src/event_handler.rs diff --git a/crates/matrix-sdk-appservice/src/event_handler.rs b/crates/matrix-sdk-appservice/src/event_handler.rs new file mode 100644 index 000000000..9a1c02e59 --- /dev/null +++ b/crates/matrix-sdk-appservice/src/event_handler.rs @@ -0,0 +1,35 @@ +use std::sync::Arc; + +use futures::future::BoxFuture; +use matrix_sdk::locks::Mutex; + +use crate::{ + ruma::api::appservice::query::{ + query_room_alias::v1 as query_room, query_user_id::v1 as query_user, + }, + AppService, +}; + +pub(crate) type AppserviceFn = + Box BoxFuture<'static, R> + Send + Sync + 'static>; + +#[derive(Default, Clone)] +pub struct EventHandler { + pub users: Arc>>>, + pub rooms: Arc>>>, +} + +impl std::fmt::Debug for EventHandler { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("EventHandler"); + match self.users.try_lock() { + Ok(lock) => debug.field("users", &lock.is_some()), + Err(_) => debug.field("users", &format_args!("")), + }; + match self.rooms.try_lock() { + Ok(lock) => debug.field("rooms", &lock.is_some()), + Err(_) => debug.field("rooms", &format_args!("")), + }; + debug.finish() + } +} diff --git a/crates/matrix-sdk-appservice/src/lib.rs b/crates/matrix-sdk-appservice/src/lib.rs index 611eea1ea..f5da02e1b 100644 --- a/crates/matrix-sdk-appservice/src/lib.rs +++ b/crates/matrix-sdk-appservice/src/lib.rs @@ -86,6 +86,7 @@ use std::{ use dashmap::DashMap; pub use error::Error; +use event_handler::AppserviceFn; use http::Uri; pub use matrix_sdk; #[doc(no_inline)] @@ -100,7 +101,10 @@ use matrix_sdk::{ use regex::Regex; use ruma::{ api::{ - appservice::Registration, + appservice::{ + query::{query_room_alias::v1 as query_room, query_user_id::v1 as query_user}, + Registration, + }, client::{ error::ErrorKind, r0::{account::register, uiaa::UiaaResponse}, @@ -113,6 +117,7 @@ use serde::de::DeserializeOwned; use tracing::{info, warn}; mod error; +pub mod event_handler; mod webserver; pub type Result = std::result::Result; @@ -203,6 +208,7 @@ pub struct AppService { server_name: ServerNameBox, registration: Arc, clients: Arc>, + event_handler: event_handler::EventHandler, } impl AppService { @@ -250,8 +256,10 @@ impl AppService { let registration = Arc::new(registration); let clients = Arc::new(DashMap::new()); let sender_localpart = registration.sender_localpart.clone(); + let event_handler = event_handler::EventHandler::default(); - let appservice = AppService { homeserver_url, server_name, registration, clients }; + let appservice = + AppService { homeserver_url, server_name, registration, clients, event_handler }; // we create and cache the [`MainUser`] by default appservice.create_and_cache_client(&sender_localpart, client_config).await?; @@ -386,6 +394,28 @@ impl AppService { Ok(()) } + /// Register a responder for queries about the existence of a user with a + /// given mxid. + /// + /// See [GET /_matrix/app/v1/users/{userId}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-users-userid). + pub async fn register_user_query( + &mut self, + handler: AppserviceFn, + ) { + *self.event_handler.users.lock().await = Some(handler); + } + + /// Register a responder for queries about the existence of a room with the + /// given alias. + /// + /// See [GET /_matrix/app/v1/rooms/{roomAlias}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-rooms-roomalias). + pub async fn register_room_query( + &mut self, + handler: AppserviceFn, + ) { + *self.event_handler.rooms.lock().await = Some(handler); + } + /// Register a virtual user by sending a [`register::Request`] to the /// homeserver /// diff --git a/crates/matrix-sdk-appservice/src/webserver/warp.rs b/crates/matrix-sdk-appservice/src/webserver/warp.rs index 3c384a296..86bf0bd05 100644 --- a/crates/matrix-sdk-appservice/src/webserver/warp.rs +++ b/crates/matrix-sdk-appservice/src/webserver/warp.rs @@ -15,7 +15,18 @@ use std::{net::ToSocketAddrs, result::Result as StdResult}; use futures::TryFutureExt; -use matrix_sdk::{bytes::Bytes, ruma}; +use matrix_sdk::{ + bytes::Bytes, + ruma::{ + self, + api::{ + appservice::query::{ + query_room_alias::v1 as query_room, query_user_id::v1 as query_user, + }, + IncomingRequest, + }, + }, +}; use serde::Serialize; use warp::{filters::BoxedFilter, path::FullPath, Filter, Rejection, Reply}; @@ -156,17 +167,35 @@ mod handlers { pub async fn user( _user_id: String, - _appservice: AppService, - _request: http::Request, + appservice: AppService, + request: http::Request, ) -> StdResult { + if let Some(user_exists) = appservice.event_handler.users.lock().await.as_mut() { + let request = + query_user::IncomingRequest::try_from_http_request(request).map_err(Error::from)?; + return if user_exists(appservice.clone(), request).await { + Ok(warp::reply::json(&String::from("{}"))) + } else { + Err(warp::reject::not_found()) + }; + } Ok(warp::reply::json(&String::from("{}"))) } pub async fn room( _room_id: String, - _appservice: AppService, - _request: http::Request, + appservice: AppService, + request: http::Request, ) -> StdResult { + if let Some(room_exists) = appservice.event_handler.rooms.lock().await.as_mut() { + let request = + query_room::IncomingRequest::try_from_http_request(request).map_err(Error::from)?; + return if room_exists(appservice.clone(), request).await { + Ok(warp::reply::json(&String::from("{}"))) + } else { + Err(warp::reject::not_found()) + }; + } Ok(warp::reply::json(&String::from("{}"))) }