summary refs log tree commit diff
path: root/src/system/message_parser.rs
blob: b404064a46d38eab7713d5f2ca668e295bde7e19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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()),
            },
        }
    }
}