1use std::collections::HashMap;
2use std::env;
3use std::fmt::Debug;
4
5use mattermost_api::client::{AuthenticationData, Mattermost};
6use tracing::trace;
7
8mod command;
9mod error;
10mod handler;
11
12use command::IntoCommand;
13use handler::Handler;
14
15pub use self::error::{Error, Result};
16
17pub struct MattermostBot {
18 handler: Handler,
19 client: Mattermost,
20}
21
22impl MattermostBot {
23 pub fn new() -> Result<Self> {
33 let mm_url =
34 env::var("MATTERMOST_URL").map_err(|_| Error::EnvVarMissing("MATTERMOST_URL"))?;
35 let mm_token =
36 env::var("MATTERMOST_TOKEN").map_err(|_| Error::EnvVarMissing("MATTERMOST_TOKEN"))?;
37 let auth_data = AuthenticationData::from_access_token(mm_token);
38 let client = Mattermost::new(&mm_url, auth_data).map_err(Error::MattermostApi)?;
39 let listener = client.clone();
40 Ok(MattermostBot {
41 handler: Handler {
42 admins: Vec::new(),
43 admin_commands: HashMap::new(),
44 commands: HashMap::new(),
45 client,
46 },
47 client: listener,
48 })
49 }
50
51 #[must_use]
52 pub fn add_command<H, Args>(mut self, name: &str, handler: H) -> Self
53 where
54 H: IntoCommand<Args>,
55 {
56 self.handler
57 .commands
58 .insert(name.into(), handler.into_command());
59 trace!("adding command: {name}");
60 self
61 }
62
63 #[must_use]
64 pub fn add_admin_command<H, Args>(mut self, name: &str, handler: H) -> Self
65 where
66 H: IntoCommand<Args>,
67 {
68 self.handler
69 .admin_commands
70 .insert(name.into(), handler.into_command());
71 trace!("adding admin command: {name}");
72 self
73 }
74
75 #[must_use]
76 pub fn add_admin(mut self, name: &str) -> Self {
77 self.handler.admins.push(name.into());
78 trace!("adding admin: {name}");
79 self
80 }
81
82 pub async fn listen(self) -> Result<()> {
92 let handler = self.handler;
93 let mut listener = self.client;
94 listener
95 .connect_to_websocket(handler)
96 .await
97 .map_err(Error::MattermostApi)
98 }
99}
100
101impl Default for MattermostBot {
102 fn default() -> Self {
109 match Self::new() {
110 Ok(bot) => bot,
111 Err(e) => panic!("Failed to create bot: {e:?}"),
112 }
113 }
114}
115
116impl Debug for MattermostBot {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 f.debug_struct("MattermostBot")
119 .field("commands", &self.handler.commands.keys())
120 .finish_non_exhaustive()
121 }
122}