From 761071dac51ccd0b66806ea310d82cba8b7e917d Mon Sep 17 00:00:00 2001 From: Devin R Date: Mon, 1 Jun 2020 07:50:45 -0400 Subject: [PATCH] base_client: fix doc grammer and consistency, group request methods together --- matrix_sdk/src/client.rs | 360 +++++++++++++++++++-------------------- 1 file changed, 177 insertions(+), 183 deletions(-) diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index e53d1619..55ad6249 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -348,22 +348,16 @@ impl Client { } /// Returns the joined rooms this client knows about. - /// - /// A `HashMap` of room id to `matrix::models::Room` pub fn joined_rooms(&self) -> Arc>>>> { self.base_client.joined_rooms() } /// Returns the invited rooms this client knows about. - /// - /// A `HashMap` of room id to `matrix::models::Room` pub fn invited_rooms(&self) -> Arc>>>> { self.base_client.invited_rooms() } /// Returns the left rooms this client knows about. - /// - /// A `HashMap` of room id to `matrix::models::Room` pub fn left_rooms(&self) -> Arc>>>> { self.base_client.left_rooms() } @@ -447,7 +441,7 @@ impl Client { /// /// # Arguments /// - /// * `session` - An session that the user already has from a + /// * `session` - A session that the user already has from a /// previous login call. pub async fn restore_login(&self, session: Session) -> Result<()> { Ok(self.base_client.restore_login(session).await?) @@ -477,7 +471,7 @@ impl Client { /// # Arguments /// /// * `alias` - The `RoomId` or `RoomAliasId` of the room to be joined. - /// An alias looks like this `#name:example.com` + /// An alias looks like `#name:example.com`. pub async fn join_room_by_id_or_alias( &self, alias: &RoomIdOrAliasId, @@ -659,7 +653,7 @@ impl Client { /// /// # Arguments /// - /// * `request` - The easiest way to create a `Request` is using the + /// * `request` - The easiest way to create this request is using the /// `MessagesRequestBuilder`. /// /// # Examples @@ -770,6 +764,180 @@ impl Client { self.send(request).await } + /// Send a room message to the homeserver. + /// + /// Returns the parsed response from the server. + /// + /// If the encryption feature is enabled this method will transparently + /// encrypt the room message if the given room is encrypted. + /// + /// # Arguments + /// + /// * `room_id` - The id of the room that should receive the message. + /// + /// * `content` - The content of the message event. + /// + /// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent` held + /// in it's unsigned field as `transaction_id`. If not given one is created for the + /// message. + /// + /// # Example + /// ```no_run + /// # use matrix_sdk::Room; + /// # use std::sync::{Arc, RwLock}; + /// # use matrix_sdk::{Client, SyncSettings}; + /// # use url::Url; + /// # use futures::executor::block_on; + /// # use ruma_identifiers::RoomId; + /// # use std::convert::TryFrom; + /// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent}; + /// # block_on(async { + /// # let homeserver = Url::parse("http://localhost:8080").unwrap(); + /// # let mut client = Client::new(homeserver).unwrap(); + /// # let room_id = RoomId::try_from("!test:localhost").unwrap(); + /// use matrix_sdk_common::uuid::Uuid; + /// + /// let content = MessageEventContent::Text(TextMessageEventContent { + /// body: "Hello world".to_owned(), + /// format: None, + /// formatted_body: None, + /// relates_to: None, + /// }); + /// let txn_id = Uuid::new_v4(); + /// client.room_send(&room_id, content, Some(txn_id)).await.unwrap(); + /// }) + /// ``` + pub async fn room_send( + &self, + room_id: &RoomId, + content: MessageEventContent, + txn_id: Option, + ) -> Result { + #[allow(unused_mut)] + let mut event_type = EventType::RoomMessage; + #[allow(unused_mut)] + let mut raw_content = serde_json::value::to_raw_value(&content)?; + + #[cfg(feature = "encryption")] + { + let encrypted = { + let room = self.base_client.get_joined_room(room_id).await; + + match room { + Some(r) => r.read().await.is_encrypted(), + None => false, + } + }; + + if encrypted { + let missing_sessions = { + let room = self.base_client.get_joined_room(room_id).await; + let room = room.as_ref().unwrap().read().await; + let users = room.members.keys(); + self.base_client.get_missing_sessions(users).await? + }; + + if !missing_sessions.is_empty() { + self.claim_one_time_keys(missing_sessions).await?; + } + + if self.base_client.should_share_group_session(room_id).await { + // TODO we need to make sure that only one such request is + // in flight per room at a time. + let response = self.share_group_session(room_id).await; + + // If one of the responses failed invalidate the group + // session as using it would end up in undecryptable + // messages. + if let Err(r) = response { + self.base_client.invalidate_group_session(room_id).await; + return Err(r); + } + } + + raw_content = serde_json::value::to_raw_value( + &self.base_client.encrypt(room_id, content).await?, + )?; + event_type = EventType::RoomEncrypted; + } + } + + let request = create_message_event::Request { + room_id: room_id.clone(), + event_type, + txn_id: txn_id.unwrap_or_else(Uuid::new_v4).to_string(), + data: raw_content, + }; + + let response = self.send(request).await?; + Ok(response) + } + + async fn send + std::fmt::Debug>( + &self, + request: Request, + ) -> Result { + let request: http::Request> = request.try_into()?; + let url = request.uri(); + let path_and_query = url.path_and_query().unwrap(); + let mut url = self.homeserver.clone(); + + url.set_path(path_and_query.path()); + url.set_query(path_and_query.query()); + + trace!("Doing request {:?}", url); + + let request_builder = match Request::METADATA.method { + HttpMethod::GET => self.http_client.get(url), + HttpMethod::POST => { + let body = request.body().clone(); + self.http_client + .post(url) + .body(body) + .header(reqwest::header::CONTENT_TYPE, "application/json") + } + HttpMethod::PUT => { + let body = request.body().clone(); + self.http_client + .put(url) + .body(body) + .header(reqwest::header::CONTENT_TYPE, "application/json") + } + HttpMethod::DELETE => unimplemented!(), + _ => panic!("Unsuported method"), + }; + + let request_builder = if Request::METADATA.requires_authentication { + let session = self.base_client.session().read().await; + + if let Some(session) = session.as_ref() { + let header_value = format!("Bearer {}", &session.access_token); + request_builder.header(AUTHORIZATION, header_value) + } else { + return Err(Error::AuthenticationRequired); + } + } else { + request_builder + }; + let mut response = request_builder.send().await?; + + trace!("Got response: {:?}", response); + + let status = response.status(); + let mut http_builder = HttpResponse::builder().status(status); + let headers = http_builder.headers_mut().unwrap(); + + for (k, v) in response.headers_mut().drain() { + if let Some(key) = k { + headers.insert(key, v); + } + } + let body = response.bytes().await?.as_ref().to_owned(); + let http_response = http_builder.body(body).unwrap(); + + Ok(::try_from(http_response)?) + } + /// Synchronize the client's state with the latest state on the server. /// /// If a `StateStore` is provided and this is the initial sync state will @@ -922,180 +1090,6 @@ impl Client { } } - async fn send + std::fmt::Debug>( - &self, - request: Request, - ) -> Result { - let request: http::Request> = request.try_into()?; - let url = request.uri(); - let path_and_query = url.path_and_query().unwrap(); - let mut url = self.homeserver.clone(); - - url.set_path(path_and_query.path()); - url.set_query(path_and_query.query()); - - trace!("Doing request {:?}", url); - - let request_builder = match Request::METADATA.method { - HttpMethod::GET => self.http_client.get(url), - HttpMethod::POST => { - let body = request.body().clone(); - self.http_client - .post(url) - .body(body) - .header(reqwest::header::CONTENT_TYPE, "application/json") - } - HttpMethod::PUT => { - let body = request.body().clone(); - self.http_client - .put(url) - .body(body) - .header(reqwest::header::CONTENT_TYPE, "application/json") - } - HttpMethod::DELETE => unimplemented!(), - _ => panic!("Unsuported method"), - }; - - let request_builder = if Request::METADATA.requires_authentication { - let session = self.base_client.session().read().await; - - if let Some(session) = session.as_ref() { - let header_value = format!("Bearer {}", &session.access_token); - request_builder.header(AUTHORIZATION, header_value) - } else { - return Err(Error::AuthenticationRequired); - } - } else { - request_builder - }; - let mut response = request_builder.send().await?; - - trace!("Got response: {:?}", response); - - let status = response.status(); - let mut http_builder = HttpResponse::builder().status(status); - let headers = http_builder.headers_mut().unwrap(); - - for (k, v) in response.headers_mut().drain() { - if let Some(key) = k { - headers.insert(key, v); - } - } - let body = response.bytes().await?.as_ref().to_owned(); - let http_response = http_builder.body(body).unwrap(); - - Ok(::try_from(http_response)?) - } - - /// Send a room message to the homeserver. - /// - /// Returns the parsed response from the server. - /// - /// If the encryption feature is enabled this method will transparently - /// encrypt the room message if the given room is encrypted. - /// - /// # Arguments - /// - /// * `room_id` - The id of the room that should receive the message. - /// - /// * `content` - The content of the message event. - /// - /// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent` held - /// in it's unsigned field as `transaction_id`. If not given one is created for the - /// message. - /// - /// # Example - /// ```no_run - /// # use matrix_sdk::Room; - /// # use std::sync::{Arc, RwLock}; - /// # use matrix_sdk::{Client, SyncSettings}; - /// # use url::Url; - /// # use futures::executor::block_on; - /// # use ruma_identifiers::RoomId; - /// # use std::convert::TryFrom; - /// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent}; - /// # block_on(async { - /// # let homeserver = Url::parse("http://localhost:8080").unwrap(); - /// # let mut client = Client::new(homeserver).unwrap(); - /// # let room_id = RoomId::try_from("!test:localhost").unwrap(); - /// use matrix_sdk_common::uuid::Uuid; - /// - /// let content = MessageEventContent::Text(TextMessageEventContent { - /// body: "Hello world".to_owned(), - /// format: None, - /// formatted_body: None, - /// relates_to: None, - /// }); - /// let txn_id = Uuid::new_v4(); - /// client.room_send(&room_id, content, Some(txn_id)).await.unwrap(); - /// }) - /// ``` - pub async fn room_send( - &self, - room_id: &RoomId, - content: MessageEventContent, - txn_id: Option, - ) -> Result { - #[allow(unused_mut)] - let mut event_type = EventType::RoomMessage; - #[allow(unused_mut)] - let mut raw_content = serde_json::value::to_raw_value(&content)?; - - #[cfg(feature = "encryption")] - { - let encrypted = { - let room = self.base_client.get_joined_room(room_id).await; - - match room { - Some(r) => r.read().await.is_encrypted(), - None => false, - } - }; - - if encrypted { - let missing_sessions = { - let room = self.base_client.get_joined_room(room_id).await; - let room = room.as_ref().unwrap().read().await; - let users = room.members.keys(); - self.base_client.get_missing_sessions(users).await? - }; - - if !missing_sessions.is_empty() { - self.claim_one_time_keys(missing_sessions).await?; - } - - if self.base_client.should_share_group_session(room_id).await { - // TODO we need to make sure that only one such request is - // in flight per room at a time. - let response = self.share_group_session(room_id).await; - - // If one of the responses failed invalidate the group - // session as using it would end up in undecryptable - // messages. - if let Err(r) = response { - self.base_client.invalidate_group_session(room_id).await; - return Err(r); - } - } - - raw_content = serde_json::value::to_raw_value( - &self.base_client.encrypt(room_id, content).await?, - )?; - event_type = EventType::RoomEncrypted; - } - } - - let request = create_message_event::Request { - room_id: room_id.clone(), - event_type, - txn_id: txn_id.unwrap_or_else(Uuid::new_v4).to_string(), - data: raw_content, - }; - - let response = self.send(request).await?; - Ok(response) - } - /// Claim one-time keys creating new Olm sessions. /// /// # Arguments