From bb6cf83a39e50017c69da2c3d653028d9ffa4fe6 Mon Sep 17 00:00:00 2001 From: Johannes Becker <66059836+johannescpk@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:57:31 +0100 Subject: [PATCH] refactor(appservice)!: Rename virtual user to appservice user --- crates/matrix-sdk-appservice/src/lib.rs | 108 +++++++++--------- .../src/{virtual_user.rs => user.rs} | 26 ++--- examples/appservice_autojoin/src/main.rs | 10 +- 3 files changed, 70 insertions(+), 74 deletions(-) rename crates/matrix-sdk-appservice/src/{virtual_user.rs => user.rs} (87%) diff --git a/crates/matrix-sdk-appservice/src/lib.rs b/crates/matrix-sdk-appservice/src/lib.rs index d83c2de0d..0b7ffe767 100644 --- a/crates/matrix-sdk-appservice/src/lib.rs +++ b/crates/matrix-sdk-appservice/src/lib.rs @@ -20,8 +20,7 @@ //! - [x] ship with functionality to configure your webserver crate or simply //! run the webserver for you //! - [x] receive and validate requests from the homeserver correctly -//! - [x] allow calling the homeserver with proper virtual user identity -//! assertion +//! - [x] allow calling the homeserver with proper user identity assertion //! - [x] have consistent room state by leveraging matrix-sdk's state store //! - [ ] provide E2EE support by leveraging matrix-sdk's crypto store //! @@ -34,7 +33,7 @@ //! //! The crate relies on the appservice registration being always in sync with //! the actual registration used by the homeserver. That's because it's required -//! for the access tokens and because membership states for virtual users are +//! for the access tokens and because membership states for appservice users are //! determined based on the registered namespaces. //! //! # Quickstart @@ -60,7 +59,7 @@ //! ) //! .build() //! .await?; -//! appservice.virtual_user(None).await?.add_event_handler( +//! appservice.user(None).await?.add_event_handler( //! |_ev: SyncRoomMemberEvent| async { //! // do stuff //! }, @@ -109,12 +108,12 @@ use tracing::{debug, info, warn}; mod error; pub mod event_handler; pub mod registration; -pub mod virtual_user; +pub mod user; mod webserver; pub use registration::AppServiceRegistration; use registration::NamespaceCache; -pub use virtual_user::VirtualUserBuilder; +pub use user::UserBuilder; pub use webserver::AppServiceRouter; pub type Result = std::result::Result; @@ -172,13 +171,13 @@ impl AppServiceBuilder { } } - /// Set the client builder to use for the virtual user. + /// Set the client builder to use for the appservice user. pub fn client_builder(mut self, client_builder: ClientBuilder) -> Self { self.client_builder = Some(client_builder); self } - /// Set the default `[RequestConfig]` to use for virtual users. + /// Set the default `[RequestConfig]` to use for appservice users. pub fn default_request_config(mut self, default_request_config: RequestConfig) -> Self { self.default_request_config = Some(default_request_config); self @@ -186,10 +185,10 @@ impl AppServiceBuilder { /// Build the AppService. /// - /// This will also construct a [`virtual_user()`][AppService::virtual_user] - /// for the `sender_localpart` of the given registration. This virtual + /// This will also construct an appservice [`user()`][AppService::user] + /// for the `sender_localpart` of the given registration. This /// user can be used to register an event handler for all incoming - /// events. Other virtual users only receive events if they're known to + /// events. Other appservice users only receive events if they're known to /// be a member of a room. pub async fn build(self) -> Result { let homeserver_url = self.homeserver_url; @@ -212,12 +211,12 @@ impl AppServiceBuilder { }; if let Some(client_builder) = self.client_builder { appservice - .virtual_user_builder(&sender_localpart) + .user_builder(&sender_localpart) .client_builder(client_builder) .build() .await?; } else { - appservice.virtual_user_builder(&sender_localpart).build().await?; + appservice.user_builder(&sender_localpart).build().await?; } Ok(appservice) } @@ -233,7 +232,7 @@ impl AppService { AppServiceBuilder::new(homeserver_url, server_name, registration) } - /// Create a virtual user client. + /// Create an appservice user client. /// /// Will create and return a client that's configured to [assert the /// identity] on outgoing homeserver requests that need authentication. @@ -242,50 +241,50 @@ impl AppService { /// based on the `localpart`. The cached client can be retrieved by calling /// this method again. /// - /// Note that if you want to do actions like joining rooms with a virtual + /// Note that if you want to do actions like joining rooms with a /// user it needs to be registered first. - /// [`register_virtual_user()`][Self::register_virtual_user] can be used + /// [`register_user()`][Self::register_user] can be used /// for that purpose. /// /// # Arguments /// - /// * `localpart` - Used for constructing the virtual user accordingly. If - /// `None` is given it uses the `sender_localpart` from the registration. + /// * `localpart` - Used for constructing the user accordingly. If `None` is + /// given it uses the `sender_localpart` from the registration. /// /// [registration]: https://matrix.org/docs/spec/application_service/r0.1.2#registration /// [assert the identity]: https://matrix.org/docs/spec/application_service/r0.1.2#identity-assertion - pub async fn virtual_user(&self, localpart: Option<&str>) -> Result { + pub async fn user(&self, localpart: Option<&str>) -> Result { let localpart = localpart.unwrap_or_else(|| self.registration.sender_localpart.as_ref()); let builder = match self.default_request_config { Some(config) => self - .virtual_user_builder(localpart) + .user_builder(localpart) .client_builder(Client::builder().request_config(config)), - None => self.virtual_user_builder(localpart), + None => self.user_builder(localpart), }; builder.build().await } - /// Same as [`virtual_user()`][Self::virtual_user] but with + /// Same as [`user()`][Self::user] but with /// the ability to pass in a [`ClientBuilder`]. /// /// Since this method is a singleton follow-up calls with different /// [`ClientBuilder`]s will be ignored. - pub async fn virtual_user_with_client_builder( + pub async fn user_with_client_builder( &self, localpart: Option<&str>, builder: ClientBuilder, ) -> Result { let localpart = localpart.unwrap_or_else(|| self.registration.sender_localpart.as_ref()); - self.virtual_user_builder(localpart).client_builder(builder).build().await + self.user_builder(localpart).client_builder(builder).build().await } - /// Create a new virtual user builder for the given `localpart`. - pub fn virtual_user_builder<'a>(&'a self, localpart: &'a str) -> VirtualUserBuilder<'a> { - VirtualUserBuilder::new(self, localpart) + /// Create a new appservice user builder for the given `localpart`. + pub fn user_builder<'a>(&'a self, localpart: &'a str) -> UserBuilder<'a> { + UserBuilder::new(self, localpart) } - /// Get the map containing all constructed virtual user clients. - pub fn virtual_users(&self) -> Arc> { + /// Get the map containing all constructed appservice user clients. + pub fn users(&self) -> Arc> { self.clients.clone() } @@ -337,8 +336,8 @@ impl AppService { *self.event_handler.rooms.lock().await = Some(handler); } - /// Register a virtual user by sending a [`register::v3::Request`] to the - /// homeserver. + /// Register an appservice user by sending a [`register::v3::Request`] to + /// the homeserver. /// /// # Arguments /// @@ -348,7 +347,7 @@ impl AppService { /// # Returns /// This function may return a UIAA response, which should be checked for /// with [`Error::as_uiaa_response()`]. - pub async fn register_virtual_user<'a>( + pub async fn register_user<'a>( &self, localpart: &'a str, device_id: Option<&'a DeviceId>, @@ -362,7 +361,7 @@ impl AppService { device_id, }); - let client = self.virtual_user(None).await?; + let client = self.user(None).await?; client.register(request).await?; self.set_user_registered(localpart).await?; @@ -371,7 +370,7 @@ impl AppService { /// Add the given localpart to the database of registered localparts. async fn set_user_registered(&self, localpart: impl AsRef) -> Result<()> { - let client = self.virtual_user(None).await?; + let client = self.user(None).await?; client .store() .set_custom_value( @@ -384,7 +383,7 @@ impl AppService { /// Get whether a localpart is listed in the database as registered. async fn is_user_registered(&self, localpart: impl AsRef) -> Result { - let client = self.virtual_user(None).await?; + let client = self.user(None).await?; let key = [USER_KEY, localpart.as_ref().as_bytes()].concat(); let store = client.store().get_custom_value(&key).await?; let registered = @@ -423,14 +422,14 @@ impl AppService { } /// Receive an incoming [transaction], pushing the contained events to - /// active virtual clients. + /// active clients. /// /// [transaction]: https://spec.matrix.org/v1.2/application-service-api/#put_matrixappv1transactionstxnid async fn receive_transaction( &self, transaction: push_events::v1::IncomingRequest, ) -> Result<()> { - let sender_localpart_client = self.virtual_user(None).await?; + let sender_localpart_client = self.user(None).await?; // Find membership events affecting members in our namespace, and update // membership accordingly @@ -461,18 +460,18 @@ impl AppService { // Spawn a task for each client that constructs and pushes a sync event let mut tasks: Vec> = Vec::new(); let transaction = Arc::new(transaction); - for virtual_user_client in self.clients.iter() { + for user_client in self.clients.iter() { let client = sender_localpart_client.clone(); - let virtual_user_client = virtual_user_client.clone(); + let user_client = user_client.clone(); let transaction = transaction.clone(); let sender_localpart = self.registration.sender_localpart.clone(); let task = tokio::spawn(async move { - let Some(user_id) = virtual_user_client.user_id() else { + let Some(user_id) = user_client.user_id() else { // The client is not logged in, skipping return Ok(()); }; - let virtual_user_localpart = user_id.localpart(); + let user_localpart = user_id.localpart(); let mut response = sync_events::v3::Response::new(transaction.txn_id.to_string()); // Clients expect events to be grouped per room, where the @@ -487,15 +486,12 @@ impl AppService { warn!("Transaction contained event with no ID"); continue; }; - let key = - &[USER_MEMBER, room_id.as_bytes(), b".", virtual_user_localpart.as_bytes()] - .concat(); + let key = &[USER_MEMBER, room_id.as_bytes(), b".", user_localpart.as_bytes()] + .concat(); let membership = match client.store().get_custom_value(key).await? { Some(value) => String::from_utf8(value).ok().map(MembershipState::from), // Assume the `sender_localpart` user is in every known room - None if virtual_user_localpart == sender_localpart => { - Some(MembershipState::Join) - } + None if user_localpart == sender_localpart => Some(MembershipState::Join), None => None, }; @@ -515,10 +511,10 @@ impl AppService { response.rooms.invite.entry(room_id).or_default(); } Some(unknown) => debug!("Unknown membership type: {unknown}"), - None => debug!("Assuming {virtual_user_localpart} is not in {room_id}"), + None => debug!("Assuming {user_localpart} is not in {room_id}"), } } - virtual_user_client.receive_transaction(&transaction.txn_id, response).await?; + user_client.receive_transaction(&transaction.txn_id, response).await?; Ok::<_, Error>(()) }); @@ -614,7 +610,7 @@ mod tests { } #[async_test] - async fn test_register_virtual_user() -> Result<()> { + async fn test_register_user() -> Result<()> { let server = MockServer::start().await; let appservice = appservice(Some(server.uri()), None).await?; @@ -637,7 +633,7 @@ mod tests { .mount(&server) .await; - appservice.register_virtual_user(localpart, None).await?; + appservice.register_user(localpart, None).await?; Ok(()) } @@ -680,7 +676,7 @@ mod tests { #[allow(clippy::mutex_atomic)] let on_state_member = Arc::new(Mutex::new(false)); - appservice.virtual_user(None).await?.add_event_handler({ + appservice.user(None).await?.add_event_handler({ let on_state_member = on_state_member.clone(); move |_ev: OriginalSyncRoomMemberEvent| { *on_state_member.lock().unwrap() = true; @@ -832,7 +828,7 @@ mod tests { #[allow(clippy::mutex_atomic)] let on_state_member = Arc::new(Mutex::new(false)); - appservice.virtual_user(None).await?.add_event_handler({ + appservice.user(None).await?.add_event_handler({ let on_state_member = on_state_member.clone(); move |_ev: OriginalSyncRoomMemberEvent| { *on_state_member.lock().unwrap() = true; @@ -901,7 +897,7 @@ mod tests { .unwrap(); let members = appservice - .virtual_user(None) + .user(None) .await? .get_room(room_id) .expect("Expected room to be available") @@ -992,8 +988,8 @@ mod tests { ]; let appservice = appservice(None, None).await?; - let alice = appservice.virtual_user(Some("_appservice_alice")).await?; - let bob = appservice.virtual_user(Some("_appservice_bob")).await?; + let alice = appservice.user(Some("_appservice_alice")).await?; + let bob = appservice.user(Some("_appservice_bob")).await?; appservice .receive_transaction(push_events::v1::IncomingRequest::new("dontcare".into(), json)) .await?; diff --git a/crates/matrix-sdk-appservice/src/virtual_user.rs b/crates/matrix-sdk-appservice/src/user.rs similarity index 87% rename from crates/matrix-sdk-appservice/src/virtual_user.rs rename to crates/matrix-sdk-appservice/src/user.rs index c088a8019..2b1eb687e 100644 --- a/crates/matrix-sdk-appservice/src/virtual_user.rs +++ b/crates/matrix-sdk-appservice/src/user.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Virtual users. +//! AppService users. use matrix_sdk::{config::RequestConfig, Client, ClientBuildError, ClientBuilder, Session}; use ruma::{ @@ -23,9 +23,9 @@ use tracing::warn; use crate::{AppService, Result}; -/// Builder for a virtual user +/// Builder for an appservice user #[derive(Debug)] -pub struct VirtualUserBuilder<'a> { +pub struct UserBuilder<'a> { appservice: &'a AppService, localpart: &'a str, device_id: Option, @@ -34,11 +34,11 @@ pub struct VirtualUserBuilder<'a> { restored_session: Option, } -impl<'a> VirtualUserBuilder<'a> { - /// Create a new virtual user builder +impl<'a> UserBuilder<'a> { + /// Create a new appservice user builder /// # Arguments /// - /// * `localpart` - The localpart of the virtual user + /// * `localpart` - The localpart of the appservice user pub fn new(appservice: &'a AppService, localpart: &'a str) -> Self { Self { appservice, @@ -50,21 +50,21 @@ impl<'a> VirtualUserBuilder<'a> { } } - /// Set the device ID of the virtual user + /// Set the device ID of the appservice user pub fn device_id(mut self, device_id: Option) -> Self { self.device_id = device_id; self } - /// Sets the client builder to use for the virtual user + /// Sets the client builder to use for the appservice user pub fn client_builder(mut self, client_builder: ClientBuilder) -> Self { self.client_builder = client_builder; self } - /// Log in as the virtual user + /// Log in as the appservice user /// - /// In some cases it is necessary to log in as the virtual user, such as to + /// In some cases it is necessary to log in as the user, such as to /// upload device keys pub fn login(mut self) -> Self { self.log_in = true; @@ -74,14 +74,14 @@ impl<'a> VirtualUserBuilder<'a> { /// Restore a persisted session /// /// This is primarily useful if you enable - /// [`VirtualUserBuilder::login()`] and want to restore a session + /// [`UserBuilder::login()`] and want to restore a session /// from a previous run. pub fn restored_session(mut self, session: Session) -> Self { self.restored_session = Some(session); self } - /// Build the virtual user + /// Build the appservice user /// /// # Errors /// This function returns an error if an invalid localpart is provided. @@ -94,7 +94,7 @@ impl<'a> VirtualUserBuilder<'a> { if !(self.appservice.user_id_is_in_namespace(&user_id) || self.localpart == self.appservice.registration.sender_localpart) { - warn!("Virtual client id '{user_id}' is not in the namespace") + warn!("Client id '{user_id}' is not in the namespace") } let mut builder = self.client_builder; diff --git a/examples/appservice_autojoin/src/main.rs b/examples/appservice_autojoin/src/main.rs index eebb3efe5..798225ac5 100644 --- a/examples/appservice_autojoin/src/main.rs +++ b/examples/appservice_autojoin/src/main.rs @@ -23,11 +23,11 @@ pub async fn handle_room_member( trace!("not an appservice user: {}", event.state_key); } else if let MembershipState::Invite = event.content.membership { let user_id = UserId::parse(event.state_key.as_str())?; - if let Err(error) = appservice.register_virtual_user(user_id.localpart(), None).await { + if let Err(error) = appservice.register_user(user_id.localpart(), None).await { error_if_user_not_in_use(error)?; } - let client = appservice.virtual_user(Some(user_id.localpart())).await?; + let client = appservice.user(Some(user_id.localpart())).await?; client.join_room_by_id(room.room_id()).await?; } @@ -64,10 +64,10 @@ pub async fn main() -> anyhow::Result<()> { appservice.register_user_query(Box::new(|_, _| Box::pin(async { true }))).await; - let virtual_user = appservice.virtual_user(None).await?; + let user = appservice.user(None).await?; - virtual_user.add_event_handler_context(appservice.clone()); - virtual_user.add_event_handler( + user.add_event_handler_context(appservice.clone()); + user.add_event_handler( move |event: OriginalSyncRoomMemberEvent, room: Room, Ctx(appservice): Ctx| { handle_room_member(appservice, room, event) },