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
|
use std::collections::HashMap;
use regex::{Regex, RegexBuilder};
use serde::{Deserialize, Deserializer, de::Error};
#[derive(Deserialize)]
pub enum AutoProxyScope {
Global,
Server,
Channel
}
#[derive(Deserialize, Clone)]
pub enum PresenceMode {
Online,
Busy,
Idle,
Invisible,
}
#[derive(Deserialize, Clone)]
#[serde(tag = "mode", rename_all = "lowercase")]
pub enum AutoproxyConfig {
Member {
name: MemberName
},
Latch {
scope: AutoproxyLatchScope,
timeout_seconds: u32,
presence_indicator: bool
}
}
#[derive(Deserialize, Clone)]
#[serde(rename_all = "lowercase")]
pub enum AutoproxyLatchScope {
Global,
Server
}
#[derive(Deserialize, Clone)]
pub struct PluralkitConfig {
#[serde(deserialize_with = "parse_regex")]
pub message_pattern: Regex,
pub api_token: String,
}
#[derive(Deserialize, Clone)]
pub struct System {
pub reference_user_id: String,
pub members: Vec<Member>,
#[serde(default = "default_forward_pings")]
pub forward_pings: bool,
pub autoproxy: Option<AutoproxyConfig>,
pub pluralkit: Option<PluralkitConfig>,
}
fn default_forward_pings() -> bool {
false
}
pub type MemberName = String;
#[derive(Deserialize, Clone)]
pub struct Member {
pub name: MemberName,
#[serde(deserialize_with = "parse_regex")]
pub message_pattern: Regex,
pub discord_token: String,
pub presence: Option<PresenceMode>,
pub status: Option<String>,
}
#[derive(Deserialize)]
pub struct Config {
#[serde(flatten)]
pub systems: HashMap<String, System>
}
impl Config {
pub fn load(config_contents: String) -> Config {
let config : Config = toml::from_str(config_contents.as_str()).unwrap();
config.systems.iter().for_each(|config_system| {
let (system_name, system) = config_system;
if let Some(autoproxy) = &system.autoproxy {
if let AutoproxyConfig::Member { name } = autoproxy {
let member_matches = system.members.iter().all(|member| {
member.name == *name
});
if !member_matches {
panic!("System {} autoproxy member {} does not match a known member name", system_name, name);
}
}
}
});
return config
}
}
fn parse_regex<'de, D: Deserializer<'de>> (deserializer: D) -> Result<Regex, D::Error> {
let mut pattern = String::deserialize(deserializer)?;
if !pattern.starts_with("^") {
pattern.insert(0, '^');
}
if !pattern.ends_with("$") {
pattern.push('$');
}
RegexBuilder::new(&pattern)
.dot_matches_new_line(true)
.case_insensitive(true)
.build()
.map_err(|e| D::Error::custom(e))
}
|