summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaweł Dybiec <pawel@dybiec.info>2022-12-25 22:47:41 +0000
committerPaweł Dybiec <pawel@dybiec.info>2022-12-25 22:47:41 +0000
commit0087545a51a33182309fb60b0980e3ef45b63b6d (patch)
tree66137df60807056941ef4f8a4ac0be3bd8c0197f
parentSupport for custom message handlers (diff)
Add reply to method with example use-case
-rw-r--r--src/main.rs56
-rw-r--r--src/mattermost.rs72
2 files changed, 116 insertions, 12 deletions
diff --git a/src/main.rs b/src/main.rs
index e2a9028..36dfbb8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,57 @@
 mod mattermost;
 
+use anyhow::anyhow;
 use tokio::{self};
 use tracing::{debug, info};
 
-struct Vav{
-
-}
+struct Vav {}
 #[async_trait::async_trait]
-impl mattermost::Handler for Vav{
-    async fn handle(&self,message:serde_json::Value,client: & mattermost::Client) {
-        debug!("{message:?}");
+impl mattermost::Handler for Vav {
+    async fn handle(
+        &self,
+        value: serde_json::Value,
+        client: &mattermost::Client,
+    ) -> Result<(), anyhow::Error> {
+        debug!("{value:?}");
+        let object = value
+            .as_object()
+            .ok_or(anyhow!("Response from mattermost should be object"))?;
+        if object
+            .get("event")
+            .ok_or(anyhow!("missing event type"))?
+            .as_str()
+            .ok_or(anyhow!("event type should be a string"))?
+            != "posted"
+        {
+            return Ok(());
+        }
+        let post: serde_json::Value = serde_json::from_str(
+            object
+                .get("data")
+                .unwrap()
+                .get("post")
+                .ok_or(anyhow!("missing post field"))?
+                .as_str()
+                .ok_or(anyhow!("post should be string"))?,
+        )?;
+        debug!("Post field {post:?}");
+        let object = post
+            .as_object()
+            .ok_or(anyhow!("Post field should represent legit object"))?;
+        let message = object
+            .get("message")
+            .ok_or(anyhow!("missing message"))?
+            .as_str()
+            .ok_or(anyhow!("message should be string"))?;
+        if !message.starts_with('!') {
+            return Ok(());
+        }
+        let message = message.strip_prefix('!').unwrap();
+        match message{
+            "adres" => client.reply_to(&post, "Uniwersytet Wrocławski Instytut Informatyki; pl. Frederyka Joliot-Curie 15; 50-383 Wrocław".to_owned()).await?,
+            _ => return Err(anyhow!("Unrecognized command {message}")),
+        }
+        Ok(())
     }
 }
 
@@ -21,6 +63,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let auth = mattermost::AuthData { login, password };
     let mut client = mattermost::Client::new(auth, "https://mattermost.continuum.ii.uni.wroc.pl");
     client.update_bearer_token().await?;
-    client.handle_websocket_stream(Vav{}).await?;
+    client.handle_websocket_stream(Vav {}).await?;
     Ok(())
 }
diff --git a/src/mattermost.rs b/src/mattermost.rs
index 9b811d1..c8759c3 100644
--- a/src/mattermost.rs
+++ b/src/mattermost.rs
@@ -16,7 +16,11 @@ pub struct Client {
 
 #[async_trait::async_trait]
 pub trait Handler {
-    async fn handle(&self, message:serde_json::Value,client: &Client);
+    async fn handle(
+        &self,
+        message: serde_json::Value,
+        client: &Client,
+    ) -> Result<(), anyhow::Error>;
 }
 
 impl Client {
@@ -48,7 +52,10 @@ impl Client {
         debug!("Successfully updated bearer token");
         Ok(())
     }
-    pub(crate) async fn handle_websocket_stream<T:Handler>(&mut self, handler: T) -> Result<(), anyhow::Error> {
+    pub(crate) async fn handle_websocket_stream<T: Handler>(
+        &mut self,
+        handler: T,
+    ) -> Result<(), anyhow::Error> {
         let url = format!("{}/api/v4/websocket", self.url.replacen("http", "ws", 1));
         let (mut ws_stream, _) = connect_async(url).await?;
         let token = self
@@ -67,13 +74,18 @@ impl Client {
                     Message::Text(text) => {
                         let json: Result<serde_json::Value, _> = serde_json::from_str(&text);
                         match json {
-                            Ok(json) => {debug!("Got json {json}");handler.handle(json,&self).await;},
-                            Err(err) => warn!("Error while deserializing {err}"),
+                            Ok(json) => {
+                                // debug!("Got json: {json}");
+                                if let Err(err) = handler.handle(json, &self).await {
+                                    warn!("Handler returned error: {err}");
+                                };
+                            }
+                            Err(err) => warn!("Error while deserializing: {err}"),
                         }
                     }
                     Message::Close(_) => break,
                     _ => {
-                        debug!("Message {message:?}");
+                        debug!("Message: {message:?}");
                     }
                 },
                 Err(err) => warn!("Error {err} while reading message"),
@@ -81,4 +93,54 @@ impl Client {
         }
         Ok(())
     }
+    pub(crate) async fn reply_to(
+        &self,
+        post: &serde_json::Value,
+        reply: String,
+    ) -> Result<(), anyhow::Error> {
+        let token = self
+            .bearer_token
+            .clone()
+            .ok_or(anyhow!("Missing bearer token"))?;
+        let object = post
+            .as_object()
+            .ok_or(anyhow!("Response from mattermost should be object"))?;
+        let id = object
+            .get("id")
+            .ok_or(anyhow!("missing id"))?
+            .as_str()
+            .ok_or(anyhow!("id should be a string"))?;
+        let root_id = object
+            .get("root_id")
+            .ok_or(anyhow!("missing root_id"))?
+            .as_str()
+            .ok_or(anyhow!("root_id should be a string"))?;
+        let post_id = if root_id == "" { id } else { root_id };
+        let channel_id = object
+            .get("channel_id")
+            .ok_or(anyhow!("missing channel_id"))?
+            .as_str()
+            .ok_or(anyhow!("channel_id should be a string"))?;
+
+        debug!("Sending response");
+        let response = self
+            .client
+            .post(format!("{}/api/v4/posts", self.url))
+            .json(&json!({
+                "channel_id":channel_id,
+                "root_id":post_id,
+                "message":&reply,
+            }))
+            .header("Authorization", format!("Bearer {token}"))
+            .send()
+            .await?;
+        let status = response.status();
+        let resp = response.text().await;
+        if !status.is_success() {
+            warn!("{:?}", resp);
+            return Err(anyhow!("Error {}", status));
+        }
+        debug!("Sent response");
+        Ok(())
+    }
 }