Merge branch 'doc-fix'
commit
21b33f4e61
|
@ -348,22 +348,16 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the joined rooms this client knows about.
|
/// Returns the joined rooms this client knows about.
|
||||||
///
|
|
||||||
/// A `HashMap` of room id to `matrix::models::Room`
|
|
||||||
pub fn joined_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
pub fn joined_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
||||||
self.base_client.joined_rooms()
|
self.base_client.joined_rooms()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the invited rooms this client knows about.
|
/// Returns the invited rooms this client knows about.
|
||||||
///
|
|
||||||
/// A `HashMap` of room id to `matrix::models::Room`
|
|
||||||
pub fn invited_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
pub fn invited_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
||||||
self.base_client.invited_rooms()
|
self.base_client.invited_rooms()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the left rooms this client knows about.
|
/// Returns the left rooms this client knows about.
|
||||||
///
|
|
||||||
/// A `HashMap` of room id to `matrix::models::Room`
|
|
||||||
pub fn left_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
pub fn left_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> {
|
||||||
self.base_client.left_rooms()
|
self.base_client.left_rooms()
|
||||||
}
|
}
|
||||||
|
@ -447,7 +441,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `session` - An session that the user already has from a
|
/// * `session` - A session that the user already has from a
|
||||||
/// previous login call.
|
/// previous login call.
|
||||||
pub async fn restore_login(&self, session: Session) -> Result<()> {
|
pub async fn restore_login(&self, session: Session) -> Result<()> {
|
||||||
Ok(self.base_client.restore_login(session).await?)
|
Ok(self.base_client.restore_login(session).await?)
|
||||||
|
@ -477,7 +471,7 @@ impl Client {
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `alias` - The `RoomId` or `RoomAliasId` of the room to be joined.
|
/// * `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(
|
pub async fn join_room_by_id_or_alias(
|
||||||
&self,
|
&self,
|
||||||
alias: &RoomIdOrAliasId,
|
alias: &RoomIdOrAliasId,
|
||||||
|
@ -659,7 +653,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `request` - The easiest way to create a `Request` is using the
|
/// * `request` - The easiest way to create this request is using the
|
||||||
/// `MessagesRequestBuilder`.
|
/// `MessagesRequestBuilder`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -770,6 +764,180 @@ impl Client {
|
||||||
self.send(request).await
|
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<Uuid>,
|
||||||
|
) -> Result<create_message_event::Response> {
|
||||||
|
#[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<Request: Endpoint<ResponseError = crate::api::Error> + std::fmt::Debug>(
|
||||||
|
&self,
|
||||||
|
request: Request,
|
||||||
|
) -> Result<Request::Response> {
|
||||||
|
let request: http::Request<Vec<u8>> = 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(<Request::Response>::try_from(http_response)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Synchronize the client's state with the latest state on the server.
|
/// 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
|
/// If a `StateStore` is provided and this is the initial sync state will
|
||||||
|
@ -922,180 +1090,6 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send<Request: Endpoint<ResponseError = crate::api::Error> + std::fmt::Debug>(
|
|
||||||
&self,
|
|
||||||
request: Request,
|
|
||||||
) -> Result<Request::Response> {
|
|
||||||
let request: http::Request<Vec<u8>> = 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(<Request::Response>::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<Uuid>,
|
|
||||||
) -> Result<create_message_event::Response> {
|
|
||||||
#[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.
|
/// Claim one-time keys creating new Olm sessions.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|
Loading…
Reference in New Issue