[fractal] API: Implement types for room management, no events yet
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] API: Implement types for room management, no events yet
- Date: Thu, 6 Feb 2020 09:54:38 +0000 (UTC)
commit 0db947a00a3b26550f564d6bb923a01afd85cd54
Author: Alejandro DomÃnguez <adomu net-c com>
Date: Fri Dec 13 05:25:27 2019 +0100
API: Implement types for room management, no events yet
fractal-matrix-api/src/backend/room.rs | 424 +++++++++++----------
fractal-matrix-api/src/backend/user.rs | 22 +-
fractal-matrix-api/src/error.rs | 1 +
fractal-matrix-api/src/meson.build | 10 +
fractal-matrix-api/src/model/member.rs | 17 +-
fractal-matrix-api/src/r0.rs | 3 +
fractal-matrix-api/src/r0/media/create.rs | 18 +-
fractal-matrix-api/src/r0/membership.rs | 3 +
.../src/r0/membership/invite_user.rs | 30 ++
.../src/r0/membership/join_room_by_id_or_alias.rs | 31 ++
fractal-matrix-api/src/r0/membership/leave_room.rs | 20 +
fractal-matrix-api/src/r0/sync.rs | 1 +
.../src/r0/sync/get_joined_members.rs | 38 ++
fractal-matrix-api/src/r0/tag.rs | 2 +
fractal-matrix-api/src/r0/tag/create_tag.rs | 37 ++
fractal-matrix-api/src/r0/tag/delete_tag.rs | 29 ++
fractal-matrix-api/src/r0/typing.rs | 59 +++
fractal-matrix-api/src/serde.rs | 15 +-
fractal-matrix-api/src/util.rs | 2 +-
19 files changed, 529 insertions(+), 233 deletions(-)
---
diff --git a/fractal-matrix-api/src/backend/room.rs b/fractal-matrix-api/src/backend/room.rs
index d4c5681a..dea519a6 100644
--- a/fractal-matrix-api/src/backend/room.rs
+++ b/fractal-matrix-api/src/backend/room.rs
@@ -1,27 +1,29 @@
use log::error;
use serde_json::json;
-use reqwest::header::CONTENT_TYPE;
-use std::fs::File;
-use std::io::prelude::*;
+use ruma_identifiers::RoomId;
+use ruma_identifiers::RoomIdOrAliasId;
+use std::convert::TryFrom;
+use std::fs;
use std::sync::mpsc::Sender;
use url::Url;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
+use std::time::Duration;
use crate::error::Error;
use crate::globals;
use std::thread;
use crate::util::cache_dir_path;
+use crate::util::client_url;
use crate::util::dw_media;
use crate::util::get_prev_batch_from;
use crate::util::json_q;
use crate::util::ContentType;
use crate::util::ResultExpectLog;
use crate::util::HTTP_CLIENT;
-use crate::util::{client_url, media_url};
use crate::backend::types::BKCommand;
use crate::backend::types::BKResponse;
@@ -30,7 +32,28 @@ use crate::backend::types::BackendData;
use crate::backend::types::RoomType;
use crate::r0::filter::RoomEventFilter;
+use crate::r0::media::create::request as create_content;
+use crate::r0::media::create::Parameters as CreateContentParameters;
+use crate::r0::media::create::Response as CreateContentResponse;
+use crate::r0::membership::invite_user::request as invite_user;
+use crate::r0::membership::invite_user::Body as InviteUserBody;
+use crate::r0::membership::invite_user::Parameters as InviteUserParameters;
+use crate::r0::membership::join_room_by_id_or_alias::request as join_room_req;
+use crate::r0::membership::join_room_by_id_or_alias::Parameters as JoinRoomParameters;
+use crate::r0::membership::leave_room::request as leave_room_req;
+use crate::r0::membership::leave_room::Parameters as LeaveRoomParameters;
+use crate::r0::sync::get_joined_members::request as get_joined_members;
+use crate::r0::sync::get_joined_members::Parameters as JoinedMembersParameters;
+use crate::r0::sync::get_joined_members::Response as JoinedMembersResponse;
use crate::r0::sync::sync_events::Language;
+use crate::r0::tag::create_tag::request as create_tag;
+use crate::r0::tag::create_tag::Body as CreateTagBody;
+use crate::r0::tag::create_tag::Parameters as CreateTagParameters;
+use crate::r0::tag::delete_tag::request as delete_tag;
+use crate::r0::tag::delete_tag::Parameters as DeleteTagParameters;
+use crate::r0::typing::request as send_typing_notification;
+use crate::r0::typing::Body as TypingNotificationBody;
+use crate::r0::typing::Parameters as TypingNotificationParameters;
use crate::r0::AccessToken;
use crate::types::ExtraContent;
use crate::types::Member;
@@ -59,24 +82,23 @@ pub fn get_room_detail(
base: Url,
access_token: AccessToken,
roomid: String,
- key: String,
+ keys: String,
) -> Result<(), Error> {
let url = bk.url(
base,
&access_token,
- &format!("rooms/{}/state/{}", roomid, key),
+ &format!("rooms/{}/state/{}", roomid, keys),
vec![],
)?;
let tx = bk.tx.clone();
- let keys = key.clone();
get!(
url,
|r: JsonValue| {
let k = keys.split('.').last().unwrap();
- let value = String::from(r[&k].as_str().unwrap_or_default());
- tx.send(BKResponse::RoomDetail(Ok((roomid, key, value))))
+ let value = r[&k].as_str().map(Into::into).unwrap_or_default();
+ tx.send(BKResponse::RoomDetail(Ok((roomid, keys, value))))
.expect_log("Connection closed");
},
|err| {
@@ -140,34 +162,30 @@ pub fn get_room_members(
access_token: AccessToken,
roomid: String,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("rooms/{}/joined_members", roomid),
- vec![],
- )?;
-
let tx = bk.tx.clone();
- get!(
- url,
- |r: JsonValue| {
- let joined = r["joined"].as_object().unwrap();
- let ms: Vec<Member> = joined
- .iter()
- .map(|(mxid, member_data)| {
- let mut member: Member = serde_json::from_value(member_data.clone()).unwrap();
- member.uid = mxid.to_string();
- member
- })
- .collect();
- tx.send(BKResponse::RoomMembers(Ok((roomid, ms))))
- .expect_log("Connection closed");
- },
- |err| {
- tx.send(BKResponse::RoomMembers(Err(err)))
- .expect_log("Connection closed");
- }
- );
+
+ let room_id = RoomId::try_from(roomid.as_str())?;
+ let params = JoinedMembersParameters { access_token };
+
+ thread::spawn(move || {
+ let query = get_joined_members(base, &room_id, ¶ms)
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)?
+ .json::<JoinedMembersResponse>()
+ .map_err(Into::into)
+ })
+ .map(|response| {
+ let ms = response.joined.into_iter().map(Member::from).collect();
+
+ (room_id.to_string(), ms)
+ });
+
+ tx.send(BKResponse::RoomMembers(query))
+ .expect_log("Connection closed");
+ });
Ok(())
}
@@ -378,22 +396,29 @@ pub fn send_typing(
userid: String,
roomid: String,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("rooms/{}/typing/{}", roomid, userid),
- vec![],
- )?;
+ let tx = bk.tx.clone();
- let attrs = json!({
- "timeout": 4000,
- "typing": true
- });
+ let room_id = RoomId::try_from(roomid.as_str())?;
+ let params = TypingNotificationParameters { access_token };
+ let body = TypingNotificationBody::Typing(Duration::from_secs(4));
- let tx = bk.tx.clone();
- query!("put", url, &attrs, move |_| {}, |err| {
- tx.send(BKResponse::SendTypingError(err))
- .expect_log("Connection closed");
+ thread::spawn(move || {
+ let query = send_typing_notification(base, &room_id, &userid, ¶ms, &body)
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)
+ .map_err(Into::into)
+ });
+
+ match query {
+ Err(err) => {
+ tx.send(BKResponse::SendTypingError(err))
+ .expect_log("Connection closed");
+ }
+ _ => (),
+ }
});
Ok(())
@@ -447,27 +472,31 @@ pub fn join_room(
access_token: AccessToken,
roomid: String,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("join/{}", urlencoding::encode(&roomid)),
- vec![],
- )?;
-
let tx = bk.tx.clone();
let data = bk.data.clone();
- post!(
- url,
- move |_: JsonValue| {
- data.lock().unwrap().join_to_room = roomid.clone();
- tx.send(BKResponse::JoinRoom(Ok(())))
- .expect_log("Connection closed");
- },
- |err| {
- tx.send(BKResponse::JoinRoom(Err(err)))
- .expect_log("Connection closed");
- }
- );
+
+ let room_id_or_alias_id = RoomIdOrAliasId::try_from(roomid.as_str())?;
+ let params = JoinRoomParameters {
+ access_token,
+ server_name: Default::default(),
+ };
+
+ thread::spawn(move || {
+ let query = join_room_req(base, &room_id_or_alias_id, ¶ms)
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)
+ .map_err(Into::into)
+ })
+ .map(|_| {
+ data.lock().unwrap().join_to_room = room_id_or_alias_id.to_string();
+ });
+
+ tx.send(BKResponse::JoinRoom(query))
+ .expect_log("Connection closed");
+ });
Ok(())
}
@@ -478,25 +507,25 @@ pub fn leave_room(
access_token: AccessToken,
roomid: String,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("rooms/{}/leave", roomid),
- vec![],
- )?;
-
let tx = bk.tx.clone();
- post!(
- url,
- move |_: JsonValue| {
- tx.send(BKResponse::LeaveRoom(Ok(())))
- .expect_log("Connection closed");
- },
- |err| {
- tx.send(BKResponse::LeaveRoom(Err(err)))
- .expect_log("Connection closed");
- }
- );
+
+ let room_id = RoomId::try_from(roomid.as_str())?;
+ let params = LeaveRoomParameters { access_token };
+
+ thread::spawn(move || {
+ let query = leave_room_req(base, &room_id, ¶ms)
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)
+ .map_err(Into::into)
+ })
+ .and(Ok(()));
+
+ tx.send(BKResponse::LeaveRoom(query))
+ .expect_log("Connection closed");
+ });
Ok(())
}
@@ -628,43 +657,29 @@ pub fn set_room_avatar(
roomid: String,
avatar: String,
) -> Result<(), Error> {
- let params = &[("access_token", tk.to_string())];
- let mediaurl = media_url(&baseu, "upload", params)?;
let roomurl = bk.url(
- baseu,
+ baseu.clone(),
&tk,
&format!("rooms/{}/state/m.room.avatar", roomid),
vec![],
)?;
- let mut file = File::open(&avatar)?;
- let mut contents: Vec<u8> = vec![];
- file.read_to_end(&mut contents)?;
-
let tx = bk.tx.clone();
thread::spawn(move || {
- match put_media(mediaurl.as_str(), contents) {
- Err(err) => {
- tx.send(BKResponse::SetRoomAvatar(Err(err)))
- .expect_log("Connection closed");
- }
- Ok(js) => {
- let uri = js["content_uri"].as_str().unwrap_or_default();
- let attrs = json!({ "url": uri });
- put!(
- roomurl,
- &attrs,
- |_| {
- tx.send(BKResponse::SetRoomAvatar(Ok(())))
- .expect_log("Connection closed");
- },
- |err| {
- tx.send(BKResponse::SetRoomAvatar(Err(err)))
- .expect_log("Connection closed");
- }
- );
- }
- };
+ let query = upload_file(baseu, tk, &avatar).and_then(|response| {
+ let js = json!({ "url": response.content_uri.as_str() });
+
+ HTTP_CLIENT
+ .get_client()?
+ .put(roomurl)
+ .json(&js)
+ .send()
+ .map_err(Into::into)
+ .and(Ok(()))
+ });
+
+ tx.send(BKResponse::SetRoomAvatar(query))
+ .expect_log("Connection closed");
});
Ok(())
@@ -677,15 +692,15 @@ pub fn attach_file(
mut msg: Message,
) -> Result<(), Error> {
let fname = msg.url.clone().unwrap_or_default();
- let extra_content: Option<ExtraContent> = {
- msg.clone()
- .extra_content
- .map_or(None, |c| Some(serde_json::from_value(c).unwrap()))
- };
+ let mut extra_content: Option<ExtraContent> = msg
+ .clone()
+ .extra_content
+ .and_then(|c| serde_json::from_value(c).ok());
let thumb = extra_content
.clone()
- .map_or(String::new(), |c| c.info.thumbnail_url.unwrap_or_default());
+ .and_then(|c| c.info.thumbnail_url)
+ .unwrap_or_default();
let tx = bk.tx.clone();
let itx = bk.internal_tx.clone();
@@ -695,57 +710,65 @@ pub fn attach_file(
}
thread::spawn(move || {
- if thumb != "" {
- match upload_file(&baseu, &tk, &thumb) {
+ if !thumb.is_empty() {
+ match upload_file(baseu.clone(), tk.clone(), &thumb) {
Err(err) => {
tx.send(BKResponse::AttachedFile(Err(err)))
.expect_log("Connection closed");
}
- Ok(thumb_uri) => {
- msg.thumb = Some(thumb_uri.to_string());
- if let Some(mut xctx) = extra_content {
+ Ok(response) => {
+ let thumb_uri = response.content_uri.to_string();
+ msg.thumb = Some(thumb_uri.clone());
+ if let Some(ref mut xctx) = extra_content {
xctx.info.thumbnail_url = Some(thumb_uri);
- msg.extra_content = Some(serde_json::to_value(&xctx).unwrap());
}
+ msg.extra_content = serde_json::to_value(&extra_content).ok();
}
}
+
if let Err(_e) = std::fs::remove_file(&thumb) {
error!("Can't remove thumbnail: {}", thumb);
}
}
- match upload_file(&baseu, &tk, &fname) {
- Err(err) => {
- tx.send(BKResponse::AttachedFile(Err(err)))
- .expect_log("Connection closed");
- }
- Ok(uri) => {
- msg.url = Some(uri.to_string());
- if let Some(t) = itx {
- t.send(BKCommand::SendMsg(baseu, tk, msg.clone()))
- .expect_log("Connection closed");
- }
- tx.send(BKResponse::AttachedFile(Ok(msg)))
+ let query = upload_file(baseu.clone(), tk.clone(), &fname).map(|response| {
+ msg.url = Some(response.content_uri.to_string());
+ if let Some(t) = itx {
+ t.send(BKCommand::SendMsg(baseu, tk, msg.clone()))
.expect_log("Connection closed");
}
- };
+
+ msg
+ });
+
+ tx.send(BKResponse::AttachedFile(query))
+ .expect_log("Connection closed");
});
Ok(())
}
-fn upload_file(baseu: &Url, tk: &AccessToken, fname: &str) -> Result<String, Error> {
- let mut file = File::open(fname)?;
- let mut contents: Vec<u8> = vec![];
- file.read_to_end(&mut contents)?;
-
- let params = &[("access_token", tk.to_string())];
- let mediaurl = media_url(&baseu, "upload", params)?;
+fn upload_file(
+ base: Url,
+ access_token: AccessToken,
+ fname: &str,
+) -> Result<CreateContentResponse, Error> {
+ let params_upload = CreateContentParameters {
+ access_token,
+ filename: None,
+ };
- match put_media(mediaurl.as_str(), contents) {
- Err(err) => Err(err),
- Ok(js) => Ok(js["content_uri"].as_str().unwrap_or_default().to_string()),
- }
+ let contents = fs::read(fname)?;
+
+ create_content(base, ¶ms_upload, contents)
+ .map_err::<Error, _>(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)?
+ .json::<CreateContentResponse>()
+ .map_err(Into::into)
+ })
}
pub fn new_room(
@@ -888,32 +911,33 @@ pub fn add_to_fav(
roomid: String,
tofav: bool,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("user/{}/rooms/{}/tags/m.favourite", userid, roomid),
- vec![],
- )?;
+ let tx = bk.tx.clone();
- let attrs = json!({
- "order": 0.5,
- });
+ let room_id = RoomId::try_from(roomid.as_str())?;
- let tx = bk.tx.clone();
- let method = if tofav { "put" } else { "delete" };
- query!(
- method,
- url,
- &attrs,
- |_| {
- tx.send(BKResponse::AddedToFav(Ok((roomid.clone(), tofav))))
- .expect_log("Connection closed");
- },
- |err| {
- tx.send(BKResponse::AddedToFav(Err(err)))
- .expect_log("Connection closed");
- }
- );
+ thread::spawn(move || {
+ let request_res = if tofav {
+ let params = CreateTagParameters { access_token };
+ let body = CreateTagBody { order: Some(0.5) };
+ create_tag(base, &userid, &room_id, "m.favourite", ¶ms, &body)
+ } else {
+ let params = DeleteTagParameters { access_token };
+ delete_tag(base, &userid, &room_id, "m.favourite", ¶ms)
+ };
+
+ let query = request_res
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)
+ .map_err(Into::into)
+ })
+ .and(Ok((room_id.to_string(), tofav)));
+
+ tx.send(BKResponse::AddedToFav(query))
+ .expect_log("Connection closed");
+ });
Ok(())
}
@@ -923,41 +947,35 @@ pub fn invite(
base: Url,
access_token: AccessToken,
roomid: String,
- userid: String,
+ user_id: String,
) -> Result<(), Error> {
- let url = bk.url(
- base,
- &access_token,
- &format!("rooms/{}/invite", roomid),
- vec![],
- )?;
+ let tx = bk.tx.clone();
- let attrs = json!({
- "user_id": userid,
- });
+ let room_id = RoomId::try_from(roomid.as_str())?;
+ let params = InviteUserParameters { access_token };
+ let body = InviteUserBody { user_id };
- let tx = bk.tx.clone();
- post!(url, &attrs, |_| {}, |err| {
- tx.send(BKResponse::InviteError(err))
- .expect_log("Connection closed");
+ thread::spawn(move || {
+ let query = invite_user(base, &room_id, ¶ms, &body)
+ .map_err(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)
+ .map_err(Into::into)
+ });
+
+ match query {
+ Err(err) => {
+ let _ = tx.send(BKResponse::InviteError(err));
+ }
+ _ => (),
+ }
});
Ok(())
}
-fn put_media(url: &str, file: Vec<u8>) -> Result<JsonValue, Error> {
- let (mime, _) = gio::content_type_guess(None, &file);
-
- HTTP_CLIENT
- .get_client()?
- .post(url)
- .body(file)
- .header(CONTENT_TYPE, mime.to_string())
- .send()?
- .json()
- .or(Err(Error::BackendError))
-}
-
pub fn set_language(
bk: &Backend,
access_token: AccessToken,
diff --git a/fractal-matrix-api/src/backend/user.rs b/fractal-matrix-api/src/backend/user.rs
index 542b97ea..a76953da 100644
--- a/fractal-matrix-api/src/backend/user.rs
+++ b/fractal-matrix-api/src/backend/user.rs
@@ -11,7 +11,6 @@ use crate::util::semaphore;
use crate::util::ContentType;
use crate::util::ResultExpectLog;
use crate::util::HTTP_CLIENT;
-use reqwest::header::HeaderValue;
use std::convert::TryInto;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
@@ -372,18 +371,15 @@ pub fn set_user_avatar(
fs::read(&avatar)
.map_err(Into::into)
.and_then(|contents| {
- let (mime, _) = gio::content_type_guess(None, &contents);
- let mime_value = HeaderValue::from_str(&mime).or(Err(Error::BackendError))?;
- let upload_response =
- create_content(base.clone(), ¶ms_upload, contents, Some(mime_value))
- .map_err::<Error, _>(Into::into)
- .and_then(|request| {
- HTTP_CLIENT
- .get_client()?
- .execute(request)?
- .json::<CreateContentResponse>()
- .map_err(Into::into)
- })?;
+ let upload_response = create_content(base.clone(), ¶ms_upload, contents)
+ .map_err::<Error, _>(Into::into)
+ .and_then(|request| {
+ HTTP_CLIENT
+ .get_client()?
+ .execute(request)?
+ .json::<CreateContentResponse>()
+ .map_err(Into::into)
+ })?;
let params_avatar = SetAvatarUrlParameters { access_token };
let body = SetAvatarUrlBody {
diff --git a/fractal-matrix-api/src/error.rs b/fractal-matrix-api/src/error.rs
index 13f82f65..08d02ad9 100644
--- a/fractal-matrix-api/src/error.rs
+++ b/fractal-matrix-api/src/error.rs
@@ -27,6 +27,7 @@ derror!(url::ParseError, Error::BackendError);
derror!(io::Error, Error::BackendError);
derror!(gio::Error, Error::BackendError);
derror!(regex::Error, Error::BackendError);
+derror!(ruma_identifiers::Error, Error::BackendError);
derror!(SystemTimeError, Error::BackendError);
derror!(serde_json::Error, Error::CacheError);
diff --git a/fractal-matrix-api/src/meson.build b/fractal-matrix-api/src/meson.build
index 9df5e735..c4b1892b 100644
--- a/fractal-matrix-api/src/meson.build
+++ b/fractal-matrix-api/src/meson.build
@@ -29,30 +29,40 @@ api_sources = files(
'r0/contact/request_verification_token_msisdn.rs',
'r0/directory/post_public_rooms.rs',
'r0/media/create.rs',
+ 'r0/membership/invite_user.rs',
+ 'r0/membership/join_room_by_id_or_alias.rs',
+ 'r0/membership/leave_room.rs',
'r0/profile/get_display_name.rs',
'r0/profile/get_profile.rs',
'r0/profile/set_avatar_url.rs',
'r0/profile/set_display_name.rs',
'r0/search/user.rs',
'r0/server/domain_info.rs',
+ 'r0/sync/get_joined_members.rs',
'r0/sync/sync_events.rs',
+ 'r0/tag/create_tag.rs',
+ 'r0/tag/delete_tag.rs',
'r0/thirdparty/get_supported_protocols.rs',
'r0/account.rs',
'r0/contact.rs',
'r0/directory.rs',
'r0/filter.rs',
'r0/media.rs',
+ 'r0/membership.rs',
'r0/profile.rs',
'r0/search.rs',
'r0/server.rs',
'r0/sync.rs',
+ 'r0/tag.rs',
'r0/thirdparty.rs',
+ 'r0/typing.rs',
'cache.rs',
'client.rs',
'error.rs',
'globals.rs',
'identity.rs',
'lib.rs',
+ 'meson.build',
'r0.rs',
'serde.rs',
'types.rs',
diff --git a/fractal-matrix-api/src/model/member.rs b/fractal-matrix-api/src/model/member.rs
index 3f9ae5cd..160beae8 100644
--- a/fractal-matrix-api/src/model/member.rs
+++ b/fractal-matrix-api/src/model/member.rs
@@ -1,9 +1,10 @@
use crate::r0::search::user::User;
+use crate::r0::sync::get_joined_members::RoomMember;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url;
-// TODO: Remove this and use only crate::r0::search::user::User
+// TODO: Make this non-(de)serializable
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Member {
// The mxid is either inside the json object, or outside of it.
@@ -43,5 +44,19 @@ impl From<User> for Member {
}
}
+impl From<(String, RoomMember)> for Member {
+ fn from(uid_roommember: (String, RoomMember)) -> Self {
+ Member {
+ uid: uid_roommember.0,
+ alias: uid_roommember.1.display_name,
+ avatar: uid_roommember
+ .1
+ .avatar_url
+ .as_ref()
+ .map(ToString::to_string),
+ }
+ }
+}
+
// hashmap userid -> Member
pub type MemberList = HashMap<String, Member>;
diff --git a/fractal-matrix-api/src/r0.rs b/fractal-matrix-api/src/r0.rs
index 46c5ae18..9b7e03e8 100644
--- a/fractal-matrix-api/src/r0.rs
+++ b/fractal-matrix-api/src/r0.rs
@@ -3,11 +3,14 @@ pub mod contact;
pub mod directory;
pub mod filter;
pub mod media;
+pub mod membership;
pub mod profile;
pub mod search;
pub mod server;
pub mod sync;
+pub mod tag;
pub mod thirdparty;
+pub mod typing;
use serde::{Deserialize, Serialize, Serializer};
use std::convert::TryFrom;
diff --git a/fractal-matrix-api/src/r0/media/create.rs b/fractal-matrix-api/src/r0/media/create.rs
index 4080d973..c1f95dac 100644
--- a/fractal-matrix-api/src/r0/media/create.rs
+++ b/fractal-matrix-api/src/r0/media/create.rs
@@ -1,6 +1,6 @@
use crate::r0::AccessToken;
use crate::serde::url as serde_url;
-use reqwest::header::{HeaderValue, CONTENT_TYPE};
+use reqwest::header::CONTENT_TYPE;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
@@ -19,16 +19,8 @@ pub struct Response {
pub content_uri: Url,
}
-pub fn request(
- base: Url,
- params: &Parameters,
- file: Vec<u8>,
- content_type: Option<HeaderValue>,
-) -> Result<Request, Error> {
- let header = content_type
- .map(|mime| (CONTENT_TYPE, mime))
- .into_iter()
- .collect();
+pub fn request(base: Url, params: &Parameters, contents: Vec<u8>) -> Result<Request, Error> {
+ let (mime, _) = gio::content_type_guess(None, &contents);
let url = base
.join("/_matrix/media/r0/upload")
@@ -37,7 +29,7 @@ pub fn request(
Client::new()
.post(url)
.query(params)
- .body(file)
- .headers(header)
+ .body(contents)
+ .header(CONTENT_TYPE, mime.to_string())
.build()
}
diff --git a/fractal-matrix-api/src/r0/membership.rs b/fractal-matrix-api/src/r0/membership.rs
new file mode 100644
index 00000000..b20640bb
--- /dev/null
+++ b/fractal-matrix-api/src/r0/membership.rs
@@ -0,0 +1,3 @@
+pub mod invite_user;
+pub mod join_room_by_id_or_alias;
+pub mod leave_room;
diff --git a/fractal-matrix-api/src/r0/membership/invite_user.rs
b/fractal-matrix-api/src/r0/membership/invite_user.rs
new file mode 100644
index 00000000..7bb8c07e
--- /dev/null
+++ b/fractal-matrix-api/src/r0/membership/invite_user.rs
@@ -0,0 +1,30 @@
+use crate::r0::AccessToken;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Body {
+ pub user_id: String,
+}
+
+pub fn request(
+ base: Url,
+ room_id: &RoomId,
+ params: &Parameters,
+ body: &Body,
+) -> Result<Request, Error> {
+ let url = base
+ .join(&format!("/_matrix/client/r0/rooms/{}/invite", room_id))
+ .expect("Malformed URL in leave_room");
+
+ Client::new().post(url).query(params).json(body).build()
+}
diff --git a/fractal-matrix-api/src/r0/membership/join_room_by_id_or_alias.rs
b/fractal-matrix-api/src/r0/membership/join_room_by_id_or_alias.rs
new file mode 100644
index 00000000..e6141c4a
--- /dev/null
+++ b/fractal-matrix-api/src/r0/membership/join_room_by_id_or_alias.rs
@@ -0,0 +1,31 @@
+use crate::r0::AccessToken;
+use crate::serde::host_list;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomIdOrAliasId;
+use serde::Serialize;
+use url::Host;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+ #[serde(with = "host_list")]
+ #[serde(skip_serializing_if = "Vec::is_empty")]
+ pub server_name: Vec<Host>,
+}
+
+// TODO: Implement Body
+
+pub fn request(
+ base: Url,
+ room_id_or_alias: &RoomIdOrAliasId,
+ params: &Parameters,
+) -> Result<Request, Error> {
+ let url = base
+ .join(&format!("/_matrix/client/r0/join/{}", room_id_or_alias))
+ .expect("Malformed URL in join_room_by_id_or_alias");
+
+ Client::new().post(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/membership/leave_room.rs
b/fractal-matrix-api/src/r0/membership/leave_room.rs
new file mode 100644
index 00000000..9a4a5297
--- /dev/null
+++ b/fractal-matrix-api/src/r0/membership/leave_room.rs
@@ -0,0 +1,20 @@
+use crate::r0::AccessToken;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+pub fn request(base: Url, room_id: &RoomId, params: &Parameters) -> Result<Request, Error> {
+ let url = base
+ .join(&format!("/_matrix/client/r0/rooms/{}/leave", room_id))
+ .expect("Malformed URL in leave_room");
+
+ Client::new().post(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/sync.rs b/fractal-matrix-api/src/r0/sync.rs
index 78aeaf20..54e0463f 100644
--- a/fractal-matrix-api/src/r0/sync.rs
+++ b/fractal-matrix-api/src/r0/sync.rs
@@ -1 +1,2 @@
+pub mod get_joined_members;
pub mod sync_events;
diff --git a/fractal-matrix-api/src/r0/sync/get_joined_members.rs
b/fractal-matrix-api/src/r0/sync/get_joined_members.rs
new file mode 100644
index 00000000..e8776c39
--- /dev/null
+++ b/fractal-matrix-api/src/r0/sync/get_joined_members.rs
@@ -0,0 +1,38 @@
+use crate::r0::AccessToken;
+use crate::serde::option_url;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Response {
+ #[serde(default)]
+ pub joined: HashMap<String, RoomMember>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct RoomMember {
+ pub display_name: Option<String>,
+ #[serde(with = "option_url")]
+ pub avatar_url: Option<Url>,
+}
+
+pub fn request(base: Url, room_id: &RoomId, params: &Parameters) -> Result<Request, Error> {
+ let url = base
+ .join(&format!(
+ "/_matrix/client/r0/rooms/{}/joined_members",
+ room_id
+ ))
+ .expect("Malformed URL in get_joined_members");
+
+ Client::new().get(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/tag.rs b/fractal-matrix-api/src/r0/tag.rs
new file mode 100644
index 00000000..0a3f29ca
--- /dev/null
+++ b/fractal-matrix-api/src/r0/tag.rs
@@ -0,0 +1,2 @@
+pub mod create_tag;
+pub mod delete_tag;
diff --git a/fractal-matrix-api/src/r0/tag/create_tag.rs b/fractal-matrix-api/src/r0/tag/create_tag.rs
new file mode 100644
index 00000000..e143d604
--- /dev/null
+++ b/fractal-matrix-api/src/r0/tag/create_tag.rs
@@ -0,0 +1,37 @@
+use crate::r0::AccessToken;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Debug, Clone, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Body {
+ // TODO: Restrict values to the range [0.0, 1.0]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub order: Option<f64>,
+}
+
+pub fn request(
+ base: Url,
+ user_id: &str,
+ room_id: &RoomId,
+ tag: &str,
+ params: &Parameters,
+ body: &Body,
+) -> Result<Request, Error> {
+ let url = base
+ .join(&format!(
+ "/_matrix/client/r0/user/{}/rooms/{}/tags/{}",
+ user_id, room_id, tag
+ ))
+ .expect("Malformed URL in create_tag");
+
+ Client::new().put(url).query(params).json(body).build()
+}
diff --git a/fractal-matrix-api/src/r0/tag/delete_tag.rs b/fractal-matrix-api/src/r0/tag/delete_tag.rs
new file mode 100644
index 00000000..6c116725
--- /dev/null
+++ b/fractal-matrix-api/src/r0/tag/delete_tag.rs
@@ -0,0 +1,29 @@
+use crate::r0::AccessToken;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Debug, Clone, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+pub fn request(
+ base: Url,
+ user_id: &str,
+ room_id: &RoomId,
+ tag: &str,
+ params: &Parameters,
+) -> Result<Request, Error> {
+ let url = base
+ .join(&format!(
+ "/_matrix/client/r0/user/{}/rooms/{}/tags/{}",
+ user_id, room_id, tag
+ ))
+ .expect("Malformed URL in delete_tag");
+
+ Client::new().delete(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/typing.rs b/fractal-matrix-api/src/r0/typing.rs
new file mode 100644
index 00000000..473a023d
--- /dev/null
+++ b/fractal-matrix-api/src/r0/typing.rs
@@ -0,0 +1,59 @@
+use crate::r0::AccessToken;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use ruma_identifiers::RoomId;
+use serde::ser::SerializeMap;
+use serde::Serialize;
+use serde::Serializer;
+use std::time::Duration;
+use url::Url;
+
+#[derive(Debug, Clone, Serialize)]
+pub struct Parameters {
+ pub access_token: AccessToken,
+}
+
+#[derive(Clone, Debug)]
+pub enum Body {
+ StopTyping,
+ Typing(Duration),
+}
+
+impl Serialize for Body {
+ fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match self {
+ Body::StopTyping => {
+ let mut serialized_map = ser.serialize_map(Some(1))?;
+ serialized_map.serialize_entry("typing", &false)?;
+ serialized_map.end()
+ }
+ Body::Typing(dur) => {
+ let mut serialized_map = ser.serialize_map(Some(2))?;
+ serialized_map.serialize_entry("typing", &true)?;
+ serialized_map.serialize_entry("timeout", &dur.as_millis())?;
+ serialized_map.end()
+ }
+ }
+ }
+}
+
+pub fn request(
+ base: Url,
+ room_id: &RoomId,
+ user_id: &str,
+ params: &Parameters,
+ body: &Body,
+) -> Result<Request, Error> {
+ let url = base
+ .join(&format!(
+ "/_matrix/client/r0/rooms/{}/typing/{}",
+ room_id, user_id,
+ ))
+ .expect("Malformed URL in typing");
+
+ Client::new().put(url).query(params).json(body).build()
+}
diff --git a/fractal-matrix-api/src/serde.rs b/fractal-matrix-api/src/serde.rs
index 3076ae8e..47a02df0 100644
--- a/fractal-matrix-api/src/serde.rs
+++ b/fractal-matrix-api/src/serde.rs
@@ -109,15 +109,26 @@ pub mod option_host {
}
}
+pub mod host_list {
+ use serde::ser::Serializer;
+ use url::Host;
+
+ pub fn serialize<S>(host_list: &[Host], ser: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ ser.collect_seq(host_list.iter().map(ToString::to_string))
+ }
+}
+
pub mod duration_as_millis {
use serde::Serializer;
use std::time::Duration;
- // TODO: use as_millis when duration_as_u128 is stable
pub fn serialize<S>(duration: &Duration, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
- ser.serialize_u64(duration.as_secs() * 1000 + (duration.subsec_millis() as u64))
+ ser.serialize_u64(duration.as_millis() as u64)
}
}
diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs
index c3aa28bb..47db4fdb 100644
--- a/fractal-matrix-api/src/util.rs
+++ b/fractal-matrix-api/src/util.rs
@@ -364,7 +364,7 @@ pub fn scalar_url(base: &Url, path: &str, params: &[(&str, String)]) -> Result<U
build_url(base, &format!("api/{}", path), params)
}
-pub fn media_url(base: &Url, path: &str, params: &[(&str, String)]) -> Result<Url, Error> {
+fn media_url(base: &Url, path: &str, params: &[(&str, String)]) -> Result<Url, Error> {
build_url(base, &format!("/_matrix/media/r0/{}", path), params)
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]