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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
use serenity::{ async_trait, model::{channel::Message, error::Error, gateway::Ready}, prelude::*, }; use std::{collections::HashMap, sync::Mutex}; pub struct Handler { user_lock: Mutex<HashMap<u64, HashMap<u64, MapData>>>, } #[derive(Clone)] struct MapData { text: String, botmsg: Message, } impl Handler { pub fn new() -> Handler { Handler { user_lock: Mutex::new(HashMap::new()), } } fn add_to_map(&self, chid: u64, uid: u64, content: String, botmsg: Message) { let mut channels = self.user_lock.lock().unwrap(); if let Some(user) = channels.get_mut(&chid) { user.insert( uid, MapData { text: content, botmsg, }, ); } else { channels.insert(chid, { let mut map = HashMap::new(); map.insert( uid, MapData { text: content, botmsg, }, ); map }); } } fn get_user_lock(&self, chid: u64, uid: u64) -> Option<MapData> { if let Some(c) = self.user_lock.lock().unwrap().get_mut(&chid) { if let Some(m) = c.remove(&uid) { Some(m) } else { None } } else { None } } } #[async_trait] impl EventHandler for Handler { async fn message(&self, ctx: Context, msg: Message) { let mapdata = self.get_user_lock(msg.channel_id.0, msg.author.id.0); let prog = if let Some(d) = mapdata.clone() { Some(d.text) } else if msg.content.len() > 2 { if msg.content[..2] == *"< " { Some(String::from(&msg.content[2..])) } else { None } } else if msg.content == "<" && msg.attachments.len() > 0 { match msg.attachments[0].download().await { Ok(chars) => Some(String::from_utf8_lossy(&chars).into_owned()), Err(err) => { println!("Error downloading attachment: {:?}", err); None } } } else { None }; let input = if let Some(d) = mapdata { if let Err(err) = d.botmsg.delete(&ctx.http).await { println!("Error deleting message: {:?}", err); } Some(msg.content) } else { None }; let output = if let Some(prog) = prog { if bf_lib::wants_input(&prog) && input == None { let botmsg = msg .channel_id .say( &ctx.http, format!( "Program requires input, next message from {} will be read", msg.author.name ), ) .await .expect("Error sending message"); self.add_to_map(msg.channel_id.0, msg.author.id.0, prog, botmsg); None } else { let typing = msg.channel_id.start_typing(&ctx.http).unwrap(); let o = match bf_lib::run(&prog, input) { Ok(ok) => ok, Err(err) => err, }; typing.stop(); Some(o) } } else { None }; if let Some(o) = output { if let Err(e) = msg.channel_id.say(&ctx.http, &o).await { if let serenity::Error::Model(Error::MessageTooLong(_)) = e { if let Err(e) = msg .channel_id .send_files(&ctx.http, vec![(o.as_bytes(), "output.txt")], |m| { m.content("Program output was too long, sending as file") }) .await { println!("Error sending message: {}", e) } } else { println!("Error sending message: {}", e) } }; } } async fn ready(&self, _: Context, ready: Ready) { println!("{} is connected!", ready.user.name); } }