Advertisement
Guest User

Untitled

a guest
Nov 12th, 2024
14
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.89 KB | None | 0 0
  1.  
  2. use irc::client::Sender;
  3. use irc::proto::{chan, Command, Message};
  4. use regex::Regex;
  5. use serde::{Deserialize, Serialize};
  6. use std::borrow::BorrowMut;
  7. use std::error::Error;
  8. use std::fs;
  9. use std::path::Path;
  10. use std::sync::Arc;
  11. use std::collections::HashMap;
  12. use tokio::sync::Mutex;
  13.  
  14. pub struct KarmaHandler {
  15. ignore: Vec<String>,
  16. db: KarmaDatabase,
  17. }
  18.  
  19. #[derive(Serialize, Deserialize, Default)]
  20. pub struct KarmaItem {
  21. name: String,
  22. count: i32,
  23. whoup: HashMap<String,i32>,
  24. whodown: HashMap<String,i32>,
  25. whyup: Vec<String>,
  26. whydown: Vec<String>,
  27. }
  28.  
  29. struct KarmaDatabase {
  30. items: HashMap<String, KarmaItem>,
  31. data_dir: String,
  32. }
  33.  
  34. impl KarmaDatabase {
  35. fn new(data_dir: &str) -> Self {
  36. Self {
  37. items: HashMap::new(),
  38. data_dir: data_dir.to_string(),
  39. }
  40. }
  41.  
  42. fn load_item(&mut self, channel: &str, key: &str) -> &mut KarmaItem {
  43. let lookup = channel.to_string() + "-" + key;
  44. let filename = channel.replace("#", "-") + "-" + key;
  45.  
  46. if !self.items.contains_key(lookup.as_str()) {
  47. let path = Path::new(&self.data_dir).join(filename);
  48. if path.exists() {
  49. let data = fs::read_to_string(path).expect("Unable to read file");
  50. let item: KarmaItem = serde_json::from_str(&data).expect("Unable to parse JSON");
  51. self.items.insert(lookup.to_string(), item);
  52. } else {
  53. self.items.insert(lookup.to_string(), KarmaItem { name: lookup.to_string(), ..Default::default() });
  54. }
  55. }
  56. self.items.get_mut(lookup.as_str()).unwrap()
  57. }
  58.  
  59. fn save_item(&self, channel: &str, key: &str) {
  60. let lookup = channel.to_string() + "-" + key;
  61. let filename = channel.replace("#", "-") + "-" + key;
  62.  
  63. if let Some(item) = self.items.get(lookup.as_str()) {
  64. let path = Path::new(&self.data_dir).join(filename);
  65. let data = serde_json::to_string(item).expect("Unable to serialize JSON");
  66. fs::write(path, data).expect("Unable to write file");
  67. }
  68. }
  69.  
  70. fn sync_item(&mut self, channel: &str, key: &str) {
  71.  
  72. self.save_item(channel, key);
  73. }
  74. }
  75.  
  76. impl KarmaHandler {
  77. pub fn new() -> KarmaHandler {
  78. KarmaHandler {
  79.  
  80. db: KarmaDatabase::new("."),
  81. ignore: vec!["aristarchus".to_string()],
  82. }
  83. }
  84.  
  85. fn prekarma(&self, message: &Message) -> bool {
  86.  
  87. if let Command::PRIVMSG(ref target, ref msg) = message.command {
  88. let re_karma = Regex::new(r"^(?P<item>\([^\)]+\)|\[[^\]]+\]|\w+)(?P<mod>\+\+|--)( |$)").unwrap();
  89.  
  90. if let Some(userhost) = message.source_nickname() {
  91. if self.ignore.contains(&userhost.to_string()) {
  92. return false;
  93. }
  94. }
  95.  
  96. if let Some(captures) = re_karma.captures(msg) {
  97. if let Some(item) = captures.name("item") {
  98. if let Some(nick) = message.source_nickname() {
  99. if item.as_str() == nick {
  100. return false;
  101. } else {
  102. return true;
  103. }
  104. }
  105. }
  106. }
  107. }
  108. false
  109. }
  110.  
  111. pub async fn handle_message(&mut self, sender:&Sender, message: &Message) {
  112. if(!self.prekarma(&message))
  113. {
  114. return;
  115. }
  116.  
  117. if let Command::PRIVMSG(ref target, ref msg) = message.command {
  118.  
  119. self.handle_privmsg(sender, target, msg, message).await.unwrap();
  120. }
  121. }
  122. async fn handle_privmsg(&mut self, sender: &Sender, target: &str, msg: &str, message: &Message) -> Result<(), Box<dyn std::error::Error>> {
  123. let re_karma = Regex::new(r"^(?P<item>\([^\)]+\)|\[[^\]]+\]|\w+)(?P<mod>\+\+|--)( |$)").unwrap();
  124.  
  125. let channel = if target.starts_with("#") { target.to_lowercase() } else { "".to_string() };
  126.  
  127. let reason = msg.split('#').nth(1).map(|s| s.trim().to_string());
  128. let source = message.source_nickname().unwrap_or("");
  129. let reply = message.response_target().unwrap_or(source);
  130.  
  131.  
  132. // create a list of output strings to send to the channel
  133. let mut output = Vec::<String>::new();
  134.  
  135. for cap in re_karma.captures_iter(msg) {
  136. let item = cap.name("item").unwrap().as_str().to_lowercase();
  137. let modifier = cap.name("mod").unwrap().as_str();
  138.  
  139. let mut karma_item = self.db.load_item(channel.as_str(), &item);
  140. if modifier == "++" {
  141. karma_item.count += 1;
  142. if !karma_item.whoup.contains_key(source) {
  143. karma_item.whoup.insert(source.to_string(), 0);
  144. }
  145. *karma_item.whoup.get_mut(source).unwrap() += 1;
  146. if let Some(ref reason) = reason {
  147. if !karma_item.whyup.contains(reason) {
  148. karma_item.whyup.push(reason.clone());
  149. }
  150. }
  151. } else {
  152. karma_item.count -= 1;
  153. if !karma_item.whodown.contains_key(source) {
  154. karma_item.whodown.insert(source.to_string(), 0);
  155. }
  156. *karma_item.whodown.get_mut(source).unwrap() -= 1;
  157. if let Some(ref reason) = reason {
  158. if !karma_item.whydown.contains(reason) {
  159. karma_item.whydown.push(reason.clone());
  160. }
  161. }
  162. }
  163. output.push(format!("{}: {}", item, karma_item.count));
  164.  
  165. self.db.sync_item(channel.as_str(), &item);
  166. }
  167.  
  168. sender.send_privmsg(reply, output.join(", ")).unwrap();
  169.  
  170.  
  171.  
  172.  
  173. Ok(())
  174. }
  175. }
  176.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement