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
use crate::irc::types::Message as IrcMessage; use hashbrown::HashMap; /// Convert an IRC-like message type into something that the Twitch commands can be parsed from /// /// Refer to this form when implementing this trait: /// /// raw string form: `@tags :prefix command args :data\r\n` /// /// Example: /** ``` use twitchchat::conversion::{TagType, ArgsType}; struct MyPrivMsg { tags: hashbrown::HashMap<String, String>, sender: String, channel: String, data: String, } impl MyPrivMsg { pub fn new<S: ToString>(channel: S, sender: S, data: S, tags: &[(S, S)]) -> Self { Self { tags: tags .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect(), channel: channel.to_string(), sender: sender.to_string(), data: data.to_string(), } } } impl twitchchat::ToMessage for MyPrivMsg { fn tags(&self) -> Option<TagType<'_>> { Some(TagType::Map(&self.tags)) } fn prefix(&self) -> Option<&str> { Some(self.sender.as_str()) } fn command(&self) -> Option<&str> { Some("PRIVMSG") } fn args(&self) -> Option<ArgsType<'_>> { Some(ArgsType::Raw(self.channel.as_str())) } fn data(&self) -> Option<&str> { Some(self.data.as_str()) } } let msg = MyPrivMsg::new( "test_channel", "museun", "hello world", &[("color", "#FF4500"), ("display-name", "Museun")], ); let twitch_msg = twitchchat::Message::parse(msg); let pm = match twitch_msg { twitchchat::Message::PrivMsg(pm) => pm, _ => unreachable!(), }; assert_eq!(pm.user(), "museun"); assert_eq!(pm.channel(), "#test_channel"); assert_eq!(pm.message(), "hello world"); assert_eq!(pm.color().unwrap().kind, twitchchat::TwitchColor::OrangeRed); ``` **/ pub trait ToMessage { /// Get the tags portion of the IRC message fn tags(&self) -> Option<TagType<'_>>; /// Get the prefix portion of the IRC message fn prefix(&self) -> Option<&str>; /// Get the command portion of the IRC message fn command(&self) -> Option<&str>; /// Get the args portion of the IRC message fn args(&self) -> Option<ArgsType<'_>>; /// Get the data portion of the IRC message fn data(&self) -> Option<&str>; } /// A representation of IRCv3 tags, a raw string or a Vec of Key-Vals pub enum TagType<'a> { /// Raw string Raw(&'a str), /// List of Key -> Values (owned) List(&'a Vec<(String, String)>), /// Map of Key -> Values (owned) Map(&'a HashMap<String, String>), } /// A representation of the args list portion of the IRC message pub enum ArgsType<'a> { /// A raw string Raw(&'a str), /// A list of parts parsed from the whitespace-separated raw string List(&'a Vec<String>), } impl ToMessage for IrcMessage { fn tags(&self) -> Option<TagType<'_>> { match self { IrcMessage::Unknown { tags, .. } => Some(TagType::Map(&tags.0)), _ => None, } } fn prefix(&self) -> Option<&str> { match self { IrcMessage::Unknown { prefix: Some(crate::irc::types::Prefix::User { nick, .. }), .. } => Some(&nick), _ => None, } } fn command(&self) -> Option<&str> { match self { IrcMessage::Unknown { head, .. } => Some(&head), _ => None, } } fn args(&self) -> Option<ArgsType<'_>> { match self { IrcMessage::Unknown { args, .. } => Some(ArgsType::List(&args)), _ => None, } } fn data(&self) -> Option<&str> { match self { IrcMessage::Unknown { tail, .. } => tail.as_ref().map(String::as_str), _ => None, } } }