1use crate::error::Error;
2use serde::Serialize;
3use serde_json::{json, Value};
4
5pub trait WecomMessage {
6 fn msg_type(&self) -> MessageType;
7 fn key(&self) -> String;
8 fn value(&self) -> impl Serialize
9 where
10 Self: Serialize,
11 {
12 self
13 }
14}
15
16#[derive(Debug, Serialize)]
17pub enum MessageType {
18 Text,
19 Image,
20 Audio,
21 Video,
22 File,
23 TextCard,
24 News,
25 Markdown,
26}
27
28#[derive(Debug)]
29pub struct MessageBuilder {
30 users: Option<String>,
31 groups: Option<String>,
32 tags: Option<String>,
33 agent_id: Option<usize>,
34 safe: i64,
35 enable_id_trans: i64,
36 enable_duplicate_check: i64,
37 duplicate_check_interval: usize,
38}
39
40impl Default for MessageBuilder {
41 fn default() -> Self {
42 Self {
43 users: None,
44 groups: None,
45 tags: None,
46 agent_id: None,
47 safe: 0,
48 enable_id_trans: 0,
49 enable_duplicate_check: 0,
50 duplicate_check_interval: 1800,
51 }
52 }
53}
54
55impl MessageBuilder {
56 pub fn new() -> Self {
57 Self::default()
58 }
59
60 pub fn to_users(mut self, users: Vec<&str>) -> Self {
61 self.users = Some(
62 users
63 .iter()
64 .fold("".to_string(), |acc, &u| format!("{acc}|{u}"))
65 .trim_start_matches('|')
66 .to_string(),
67 );
68 self
69 }
70
71 pub fn to_groups(mut self, groups: Vec<&str>) -> Self {
72 self.groups = Some(
73 groups
74 .iter()
75 .fold("".to_string(), |acc, &u| format!("{acc}|{u}"))
76 .trim_start_matches('|')
77 .to_string(),
78 );
79 self
80 }
81
82 pub fn to_tags(mut self, tags: Vec<&str>) -> Self {
83 self.tags = Some(
84 tags.iter()
85 .fold("".to_string(), |acc, &u| format!("{acc}|{u}"))
86 .trim_start_matches('|')
87 .to_string(),
88 );
89 self
90 }
91
92 pub fn from_agent(mut self, agent_id: usize) -> Self {
93 self.agent_id = Some(agent_id);
94 self
95 }
96
97 pub fn with_safe(mut self, safe: i64) -> Self {
98 self.safe = safe;
99 self
100 }
101 pub fn with_enable_id_trans(mut self, enable_id_trans: i64) -> Self {
102 self.enable_id_trans = enable_id_trans;
103 self
104 }
105 pub fn with_enable_duplicate_check(mut self, enable_duplicate_check: i64) -> Self {
106 self.enable_duplicate_check = enable_duplicate_check;
107 self
108 }
109 pub fn with_duplicate_check_interval(mut self, duplicate_check_interval: usize) -> Self {
110 self.duplicate_check_interval = duplicate_check_interval;
111 self
112 }
113
114 pub fn build<T>(&self, content: T) -> Result<Value, Box<dyn std::error::Error>>
115 where
116 T: Serialize + WecomMessage,
117 {
118 if [&self.users, &self.groups, &self.tags]
119 .iter()
120 .all(|&x| x.is_none())
121 {
122 return Err(Box::new(Error::new(-999, "收件人不可为空".to_string())));
123 }
124
125 if self.agent_id.is_none() {
126 return Err(Box::new(Error::new(-999, "AgentID不可为空".to_string())));
127 }
128
129 let empty_string = "".to_string();
130 let mut j = json!({
131 "touser": self.users.clone().unwrap_or(empty_string.clone()),
132 "toparty": self.groups.clone().unwrap_or(empty_string.clone()),
133 "totag": self.tags.clone().unwrap_or(empty_string.clone()),
134 "msgtype": match content.msg_type() {
135 MessageType::Audio => "voice".to_string(),
136 MessageType::File => "file".to_string(),
137 MessageType::Image => "image".to_string(),
138 MessageType::Markdown => "markdown".to_string(),
139 MessageType::News => "news".to_string(),
140 MessageType::Text => "text".to_string(),
141 MessageType::TextCard => "textcard".to_string(),
142 MessageType::Video => "video".to_string(),
143 },
144 "agentid": self.agent_id.expect("AgentID should not be None"),
145 "safe": self.safe,
146 "enable_id_trans": self.enable_id_trans,
147 "enable_duplicate_check": self.enable_duplicate_check,
148 "duplicate_check_interval": self.duplicate_check_interval,});
149 j.as_object_mut()
150 .unwrap()
151 .insert(content.key(), serde_json::to_value(content.value())?);
152 Ok(j)
153 }
154}
155
156#[derive(Debug, Serialize, PartialEq)]
173pub struct Text {
174 content: String,
175}
176
177impl Text {
178 pub fn new(content: String) -> Self {
179 Self { content }
180 }
181}
182
183impl WecomMessage for Text {
184 fn msg_type(&self) -> MessageType {
185 MessageType::Text
186 }
187
188 fn key(&self) -> String {
189 "text".to_string()
190 }
191}
192
193pub struct ImageMsg {}
209
210pub struct AudioMsg {}
225
226pub struct VideoMsg {}
244
245pub struct FileMsg {}
261
262pub struct TextCardMsg {}
281
282pub struct MarkDownMsg {}
297
298#[cfg(test)]
299mod test {
300 use std::vec;
301
302 use super::*;
303 #[test]
304 fn test_builder() {
305 let content = Text::new("hello text!".to_string());
306 let msg = MessageBuilder::default()
307 .to_users(vec!["robin", "tom", "Alex", "Susanna"])
308 .to_groups(vec!["a", "b", "c"])
309 .to_tags(vec!["x", "y", "z"])
310 .from_agent(1)
311 .with_safe(1)
312 .with_enable_id_trans(1)
313 .with_enable_duplicate_check(1)
314 .with_duplicate_check_interval(800)
315 .build(content)
316 .expect("Massage should be built");
317 let raw = json!({
318 "touser" : "robin|tom|Alex|Susanna",
319 "toparty" : "a|b|c",
320 "totag" : "x|y|z",
321 "msgtype": "text",
322 "agentid" : 1,
323 "safe": 1,
324 "enable_id_trans": 1,
325 "enable_duplicate_check": 1,
326 "duplicate_check_interval": 800,
327 "text": {
328 "content": "hello text!"
329 },
330 });
331 assert_eq!(msg, serde_json::to_value(raw).unwrap());
332 }
333}