[fractal] API: Add get_message_events endpoint



commit 378e04cc30645d478a90700c4309b6e3f22d8678
Author: Alejandro Domínguez <adomu net-c com>
Date:   Mon Feb 10 05:49:57 2020 +0100

    API: Add get_message_events endpoint

 fractal-matrix-api/src/backend/media.rs            | 102 ++++++++++-----------
 fractal-matrix-api/src/r0.rs                       |   5 +
 fractal-matrix-api/src/r0/filter.rs                |  20 +++-
 fractal-matrix-api/src/r0/message.rs               |   1 +
 .../src/r0/message/get_message_events.rs           |  51 +++++++++++
 fractal-matrix-api/src/r0/search/user.rs           |   5 +-
 6 files changed, 128 insertions(+), 56 deletions(-)
---
diff --git a/fractal-matrix-api/src/backend/media.rs b/fractal-matrix-api/src/backend/media.rs
index 835aa531..68ce863e 100644
--- a/fractal-matrix-api/src/backend/media.rs
+++ b/fractal-matrix-api/src/backend/media.rs
@@ -2,7 +2,6 @@ use crate::backend::types::Backend;
 use crate::error::Error;
 use crate::globals;
 use ruma_identifiers::RoomId;
-use serde_json::json;
 use std::str::Split;
 use std::sync::mpsc::Sender;
 use std::thread;
@@ -10,16 +9,19 @@ use url::Url;
 
 use crate::r0::AccessToken;
 use crate::util::cache_dir_path;
-use crate::util::client_url;
 use crate::util::download_file;
 use crate::util::dw_media;
 use crate::util::get_prev_batch_from;
-use crate::util::json_q;
 use crate::util::semaphore;
 use crate::util::ContentType;
 use crate::util::ResultExpectLog;
+use crate::util::HTTP_CLIENT;
 
 use crate::r0::filter::RoomEventFilter;
+use crate::r0::message::get_message_events::request as get_messages_events_req;
+use crate::r0::message::get_message_events::Direction as GetMessagesEventsDirection;
+use crate::r0::message::get_message_events::Parameters as GetMessagesEventsParams;
+use crate::r0::message::get_message_events::Response as GetMessagesEventsResponse;
 use crate::types::Message;
 
 pub fn get_thumb_async(bk: &Backend, baseu: Url, media: String, tx: Sender<Result<String, Error>>) {
@@ -46,15 +48,25 @@ pub fn get_media_list_async(
     tx: Sender<(Vec<Message>, String)>,
 ) {
     semaphore(bk.limit_threads.clone(), move || {
-        let media_list = get_room_media_list(
-            &baseu,
-            &access_token,
-            &room_id,
-            globals::PAGE_LIMIT,
-            first_media_id,
-            &prev_batch,
-        )
-        .unwrap_or_default();
+        let media_list = prev_batch
+            // FIXME: This should never be an empty token
+            .or_else(|| {
+                if let Some(ref id) = first_media_id {
+                    get_prev_batch_from(&baseu, &access_token, &room_id, id).ok()
+                } else {
+                    None
+                }
+            })
+            .and_then(|from| {
+                get_room_media_list(
+                    baseu,
+                    access_token,
+                    &room_id,
+                    globals::PAGE_LIMIT as u64,
+                    from,
+                ).ok()
+            })
+            .unwrap_or_default();
         tx.send(media_list).expect_log("Connection closed");
     });
 }
@@ -75,49 +87,37 @@ pub fn get_file_async(url: Url, tx: Sender<String>) -> Result<(), Error> {
 }
 
 fn get_room_media_list(
-    baseu: &Url,
-    tk: &AccessToken,
+    baseu: Url,
+    access_token: AccessToken,
     room_id: &RoomId,
-    limit: i32,
-    first_media_id: Option<String>,
-    prev_batch: &Option<String>,
+    limit: u64,
+    prev_batch: String,
 ) -> Result<(Vec<Message>, String), Error> {
-    let mut params = vec![
-        ("dir", String::from("b")),
-        ("limit", format!("{}", limit)),
-        ("access_token", tk.to_string()),
-        (
-            "filter",
-            serde_json::to_string(&RoomEventFilter {
-                contains_url: true,
-                not_types: vec!["m.sticker"],
-                ..Default::default()
-            })
-            .expect("Failed to serialize room media list request filter"),
-        ),
-    ];
-
-    match prev_batch {
-        Some(ref pb) => params.push(("from", pb.clone())),
-        None => {
-            if let Some(id) = first_media_id {
-                params.push(("from", get_prev_batch_from(baseu, tk, room_id, &id)?))
-            }
-        }
+    let params = GetMessagesEventsParams {
+        access_token,
+        from: prev_batch,
+        to: None,
+        dir: GetMessagesEventsDirection::Backward,
+        limit,
+        filter: RoomEventFilter {
+            contains_url: true,
+            not_types: vec!["m.sticker"],
+            ..Default::default()
+        },
     };
 
-    let path = format!("rooms/{}/messages", room_id);
-    let url = client_url(baseu, &path, &params)?;
-
-    let r = json_q("get", url, &json!(null))?;
-    let array = r["chunk"].as_array();
-    let prev_batch = r["end"].to_string().trim_matches('"').to_string();
-    if array.is_none() || array.unwrap().is_empty() {
-        return Ok((vec![], prev_batch));
-    }
+    get_messages_events_req(baseu, &params, room_id)
+        .map_err(Into::into)
+        .and_then(|request| {
+            let response = HTTP_CLIENT
+                .get_client()?
+                .execute(request)?
+                .json::<GetMessagesEventsResponse>()?;
 
-    let evs = array.unwrap().iter().rev();
-    let media_list = Message::from_json_events_iter(room_id, evs)?;
+            let prev_batch = response.end.unwrap_or_default();
+            let evs = response.chunk.iter().rev();
+            let media_list = Message::from_json_events_iter(room_id, evs)?;
 
-    Ok((media_list, prev_batch))
+            Ok((media_list, prev_batch))
+        })
 }
diff --git a/fractal-matrix-api/src/r0.rs b/fractal-matrix-api/src/r0.rs
index 9b7e03e8..b4c7e058 100644
--- a/fractal-matrix-api/src/r0.rs
+++ b/fractal-matrix-api/src/r0.rs
@@ -4,6 +4,7 @@ pub mod directory;
 pub mod filter;
 pub mod media;
 pub mod membership;
+pub mod message;
 pub mod profile;
 pub mod search;
 pub mod server;
@@ -94,3 +95,7 @@ impl From<String> for AccessToken {
         Self(token)
     }
 }
+
+pub(crate) fn u64_is_10(number: &u64) -> bool {
+    number == &10
+}
diff --git a/fractal-matrix-api/src/r0/filter.rs b/fractal-matrix-api/src/r0/filter.rs
index f2364ff1..3571fb6a 100644
--- a/fractal-matrix-api/src/r0/filter.rs
+++ b/fractal-matrix-api/src/r0/filter.rs
@@ -88,7 +88,25 @@ pub struct RoomEventFilter<'a> {
     pub contains_url: bool,
 }
 
-pub fn serialize_filter_as_str<S>(filter: &Filter, ser: S) -> Result<S::Ok, S::Error>
+impl<'a> RoomEventFilter<'a> {
+    pub fn is_default(&self) -> bool {
+        *self == Default::default()
+    }
+}
+
+pub(crate) fn serialize_filter_as_str<S>(filter: &Filter, ser: S) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    let filter_str = serde_json::to_string(filter).expect("Malformed filter");
+
+    ser.serialize_str(&filter_str)
+}
+
+pub(crate) fn serialize_room_event_filter_as_str<S>(
+    filter: &RoomEventFilter,
+    ser: S,
+) -> Result<S::Ok, S::Error>
 where
     S: Serializer,
 {
diff --git a/fractal-matrix-api/src/r0/message.rs b/fractal-matrix-api/src/r0/message.rs
new file mode 100644
index 00000000..7a4e2571
--- /dev/null
+++ b/fractal-matrix-api/src/r0/message.rs
@@ -0,0 +1 @@
+pub mod get_message_events;
diff --git a/fractal-matrix-api/src/r0/message/get_message_events.rs 
b/fractal-matrix-api/src/r0/message/get_message_events.rs
new file mode 100644
index 00000000..7eb194da
--- /dev/null
+++ b/fractal-matrix-api/src/r0/message/get_message_events.rs
@@ -0,0 +1,51 @@
+use crate::r0::filter::serialize_room_event_filter_as_str;
+use crate::r0::filter::RoomEventFilter;
+use crate::r0::u64_is_10;
+use crate::r0::AccessToken;
+use reqwest::blocking::Client;
+use reqwest::blocking::Request;
+use reqwest::Error;
+use ruma_identifiers::RoomId;
+use serde::{Deserialize, Serialize};
+use serde_json::Value as JsonValue;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters<'a> {
+    pub access_token: AccessToken,
+    pub from: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub to: Option<String>,
+    pub dir: Direction,
+    #[serde(skip_serializing_if = "u64_is_10")]
+    pub limit: u64,
+    #[serde(serialize_with = "serialize_room_event_filter_as_str")]
+    #[serde(skip_serializing_if = "RoomEventFilter::is_default")]
+    pub filter: RoomEventFilter<'a>,
+}
+
+#[derive(Clone, Debug, Serialize)]
+pub enum Direction {
+    #[serde(rename = "b")]
+    Backward,
+    #[serde(rename = "f")]
+    Forward,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Response {
+    pub start: Option<String>,
+    pub end: Option<String>,
+    #[serde(default)]
+    pub chunk: Vec<JsonValue>,
+    #[serde(default)]
+    pub state: Vec<JsonValue>,
+}
+
+pub fn request(base: Url, params: &Parameters, room_id: &RoomId) -> Result<Request, Error> {
+    let url = base
+        .join(&format!("/_matrix/client/r0/rooms/{}/messages", room_id))
+        .expect("Malformed URL in user_directory");
+
+    Client::new().get(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/search/user.rs b/fractal-matrix-api/src/r0/search/user.rs
index 08be068a..55e97afa 100644
--- a/fractal-matrix-api/src/r0/search/user.rs
+++ b/fractal-matrix-api/src/r0/search/user.rs
@@ -1,3 +1,4 @@
+use crate::r0::u64_is_10;
 use crate::r0::AccessToken;
 use crate::serde::option_url;
 use reqwest::blocking::Client;
@@ -43,10 +44,6 @@ pub struct User {
     pub avatar_url: Option<Url>,
 }
 
-fn u64_is_10(number: &u64) -> bool {
-    number == &10
-}
-
 pub fn request(base: Url, params: &Parameters, body: &Body) -> Result<Request, Error> {
     let url = base
         .join("/_matrix/client/r0/user_directory/search")


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]