summary refs log tree commit diff
path: root/src/system/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'src/system/plugin')
-rw-r--r--src/system/plugin/autoproxy.rs143
-rw-r--r--src/system/plugin/prefixes.rs40
2 files changed, 183 insertions, 0 deletions
diff --git a/src/system/plugin/autoproxy.rs b/src/system/plugin/autoproxy.rs
new file mode 100644
index 0000000..cd24e0b
--- /dev/null
+++ b/src/system/plugin/autoproxy.rs
@@ -0,0 +1,143 @@
+use async_trait::async_trait;
+use std::sync::Arc;
+use tokio::sync::Mutex;
+use twilight_model::{channel::{Channel, Message}, id::{marker::ChannelMarker, Id}, util::Timestamp};
+use crate::system::types::{System, Member, Response};
+use super::{CommandOutcome, SeancePlugin};
+use tokio::time::sleep;
+use std::time::Duration;
+
+pub struct Autoproxy {
+    current_state: Arc<Mutex<InnerState>>,
+}
+
+#[derive(Clone)]
+enum InnerState {
+    Off,
+    LatchActive { current_member: Member, last_message: Timestamp },
+    LatchInactive,
+    Member { current_member: Member },
+}
+
+impl Autoproxy {
+    pub fn new() -> Self {
+        Self {
+            current_state: Arc::new(Mutex::new(InnerState::Off))
+        }
+    }
+}
+
+#[async_trait]
+impl SeancePlugin for Autoproxy {
+    async fn handle_command(&self, system: &System, message: &Message) -> CommandOutcome {
+        if message.content.starts_with(format!("{}auto ", system.command_prefix).as_str()) {
+            let args = message.content.replace(format!("{}auto ", system.command_prefix).as_str(), "");
+            let mut remainder = args.split_whitespace();
+            let first_word = remainder.next();
+
+            match first_word {
+                Some("off") => *self.current_state.lock().await = InnerState::Off,
+                Some("latch") => *self.current_state.lock().await = InnerState::LatchInactive,
+                Some("member") => {
+                    return CommandOutcome::Errored { message: "Member mode not supported yet".to_string() }
+                },
+                Some(other) => return CommandOutcome::Errored { message: format!("Unknown autoproxy mode: {other}") },
+                None => return CommandOutcome::Errored { message: "Must specify autoproxy mode".to_string() },
+            }
+
+            CommandOutcome::Handled
+        } else {
+            CommandOutcome::Skipped
+        }
+    }
+
+    async fn handle_message(&self, system: &System, message: &Message, response: &mut Response) {
+        if message.content.starts_with("\\") {
+            if message.content.starts_with("\\\\") {
+                if let InnerState::LatchActive {current_member: _, last_message: _} = {self.current_state.lock().await.clone()} {
+                    {*self.current_state.lock().await = InnerState::LatchInactive};
+                }
+            }
+
+            *response = Response::Noop { delete_source: message.content == "\\\\" };
+            return
+        }
+
+        if let Response::Noop { delete_source: _ } = response {
+            let current_state = {self.current_state.lock().await.clone()};
+            match current_state {
+                InnerState::Off => return,
+                InnerState::LatchInactive => return,
+                InnerState::Member { current_member } => {
+                    *response = Response::Proxy {
+                        member: current_member.clone(),
+                        content: message.content.clone(),
+                    }
+                },
+                InnerState::LatchActive { current_member, last_message: _ } => {
+                    *response = Response::Proxy {
+                        member: current_member.clone(),
+                        content: message.content.clone(),
+                    }
+                },
+            }
+
+        }
+    }
+
+    async fn post_response(&self, system: &System, message: &Message, channel: Id<ChannelMarker>, response: &Response) {
+        match response {
+            Response::Noop { delete_source } => return,
+            Response::Proxy { member, content } => {
+                let current_state = {self.current_state.lock().await.clone()};
+                match current_state {
+                    InnerState::Off => return,
+                    InnerState::Member { current_member } => return,
+                    InnerState::LatchInactive => {
+                        {*self.current_state.lock().await = InnerState::LatchActive {
+                           current_member: member.clone(),
+                           last_message: message.timestamp,
+                        }};
+
+                        let state_arc = self.current_state.clone();
+                        let sent_member = member.clone();
+                        let sent_timestamp = message.timestamp.clone();
+
+                        tokio::spawn(async move {
+                            sleep(Duration::from_secs(15 * 60)).await;
+                            let current_state = {state_arc.lock().await.clone()};
+
+                            if let InnerState::LatchActive { current_member, last_message } = current_state {
+                                if sent_member.discord_token == current_member.discord_token && sent_timestamp.as_micros() == last_message.as_micros() {
+                                    {*state_arc.lock().await = InnerState::LatchInactive};
+                                }
+                            }
+                        });
+                    },
+                    InnerState::LatchActive { current_member: _, last_message: _ } => {
+                        {*self.current_state.lock().await = InnerState::LatchActive {
+                            current_member: member.clone(),
+                            last_message: message.timestamp,
+                        }};
+
+                        let state_arc = self.current_state.clone();
+                        let sent_member = member.clone();
+                        let sent_timestamp = message.timestamp.clone();
+
+                        tokio::spawn(async move {
+                            sleep(Duration::from_secs(15 * 60)).await;
+                            let current_state = {state_arc.lock().await.clone()};
+
+                            if let InnerState::LatchActive { current_member, last_message } = current_state {
+                                if sent_member.discord_token == current_member.discord_token && sent_timestamp.as_micros() == last_message.as_micros() {
+                                    {*state_arc.lock().await = InnerState::LatchInactive};
+                                }
+                            }
+                        });
+                    },
+                }
+            },
+        }
+
+    }
+}
diff --git a/src/system/plugin/prefixes.rs b/src/system/plugin/prefixes.rs
new file mode 100644
index 0000000..a513573
--- /dev/null
+++ b/src/system/plugin/prefixes.rs
@@ -0,0 +1,40 @@
+use async_trait::async_trait;
+use twilight_model::id::{marker::ChannelMarker, Id};
+use crate::system::types::Response;
+
+use super::{CommandOutcome, SeancePlugin};
+
+pub struct ProxyPrefixes;
+
+#[async_trait]
+impl SeancePlugin for ProxyPrefixes {
+    async fn handle_command(&self, _system: &crate::system::types::System, _message: &twilight_model::channel::Message) -> CommandOutcome {
+        CommandOutcome::Skipped
+    }
+
+    async fn handle_message(&self, system: &crate::system::types::System, message: &twilight_model::channel::Message, response: &mut crate::system::types::Response) {
+        if let Response::Noop { delete_source: _ } = response {
+            for member in &system.members {
+                println!("Checking member prefix: {:?}", member.message_pattern);
+                match member.message_pattern.captures(message.content.as_str()) {
+                    None => {
+                        println!("Nope");
+                        continue;
+                    },
+                    Some(captures) => match captures.name("content") {
+                        None => continue,
+                        Some(matched_content) => {
+                            println!("Matched member prefix: {:?}", member.message_pattern);
+                            *response = Response::Proxy { member: member.clone(), content: matched_content.as_str().to_string() };
+                            return
+                        },
+                    }
+                }
+            }
+        }
+    }
+
+    async fn post_response(&self, _system: &crate::system::types::System, _message: &twilight_model::channel::Message, _channel: Id<ChannelMarker>, _response: &crate::system::types::Response) {
+        return
+    }
+}