summary refs log tree commit diff
path: root/src/system/message_parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/system/message_parser.rs')
-rw-r--r--src/system/message_parser.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/system/message_parser.rs b/src/system/message_parser.rs
new file mode 100644
index 0000000..b404064
--- /dev/null
+++ b/src/system/message_parser.rs
@@ -0,0 +1,126 @@
+use std::sync::LazyLock;
+use regex::Regex;
+
+use crate::config::{self, System};
+
+use super::{FullMessage, MemberId, MessageId, Timestamp};
+
+pub enum ParsedMessage {
+    Command(Command),
+    ProxiedMessage {
+        member_id: MemberId,
+        message_content: String,
+        latch: bool,
+    },
+    UnproxiedMessage,
+    LatchClear(MemberId),
+
+    // TODO: Figure out how to represent emotes
+    EmoteAdd(MemberId, MessageId, ()),
+    EmoteRemove(MemberId, MessageId, ()),
+}
+
+pub enum Command {
+    Edit(MessageId, String),
+    Reproxy(MessageId, MemberId),
+    Nick(MemberId, String),
+    ReloadSystemConfig,
+    ExitSéance,
+    UnknownCommand,
+}
+
+pub struct MessageParser {}
+
+static CORRECTION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+   Regex::new(r"^\*\B+$").unwrap()
+});
+
+impl MessageParser {
+    pub fn parse(message: &FullMessage, secondary_message: Option<&FullMessage>, system_config: &System, latch_state: Option<(MemberId, Timestamp)>) -> ParsedMessage {
+        if message.content == r"\\" {
+            return ParsedMessage::LatchClear(if let Some((member_id, _)) = latch_state {
+                member_id
+            } else {
+                0
+            })
+        }
+
+        if message.content.starts_with(r"\") {
+            return ParsedMessage::UnproxiedMessage
+        }
+
+        if message.content.starts_with(r"!") {
+            return ParsedMessage::Command(
+                MessageParser::parse_command(message, secondary_message, system_config, latch_state)
+            );
+        }
+
+        if CORRECTION_REGEX.is_match(message.content.as_str()) {
+            if let Some(parse) = MessageParser::check_correction(message, secondary_message) {
+                return parse
+            }
+        }
+
+        if let Some(parse) = MessageParser::check_member_patterns(message, system_config) {
+            return parse
+        }
+
+        if let Some(parse) = MessageParser::check_autoproxy(message, latch_state) {
+            return parse
+        }
+
+        // If nothing else
+        ParsedMessage::UnproxiedMessage
+    }
+
+    fn parse_command(message: &FullMessage, secondary_message: Option<&FullMessage>, system_config: &System, latch_state: Option<(MemberId, Timestamp)>) -> Command {
+        
+        // If unable to parse
+        Command::UnknownCommand
+    }
+
+    fn check_correction(message: &FullMessage, secondary_message: Option<&FullMessage>) -> Option<ParsedMessage> {
+        None
+    }
+
+    fn check_member_patterns(message: &FullMessage, system_config: &System) -> Option<ParsedMessage> {
+        let matches_prefix = system_config.members.iter().enumerate().find_map(|(member_id, member)|
+            Some((member_id, member.matches_proxy_prefix(&message)?))
+        );
+
+        if let Some((member_id, matched_content)) = matches_prefix {
+            Some(ParsedMessage::ProxiedMessage {
+                member_id,
+                message_content: matched_content.to_string(),
+                latch: true,
+            })
+        } else {
+            None
+        }
+    }
+
+    fn check_autoproxy(message: &FullMessage, latch_state: Option<(MemberId, Timestamp)>) -> Option<ParsedMessage> {
+        if let Some((member_id, _)) = latch_state {
+            Some(ParsedMessage::ProxiedMessage {
+                member_id,
+                message_content: message.content.clone(),
+                latch: true,
+            })
+        } else {
+            None
+        }
+    }
+}
+
+impl crate::config::Member {
+    pub fn matches_proxy_prefix<'a>(&self, message: &'a FullMessage) -> Option<&'a str> {
+        match self.message_pattern.captures(message.content.as_str()) {
+            None => None,
+            Some(captures) => match captures.name("content") {
+                None => None,
+                Some(matched_content) => Some(matched_content.as_str()),
+            },
+        }
+    }
+}
+