commit 5b01eca43f2ad39ab9e8e65396452bf9aa5e4d63
parent ee309c70c1f443379c91af0ad2e8ba649c0a7d1b
Author: tomvig38@gmail.com <tomvig38@gmail.com>
Date: Tue, 19 Oct 2021 08:11:15 +0000
Pliboniĝu la elektoj
Diffstat:
M | src/main.rs | | | 158 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
1 file changed, 114 insertions(+), 44 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -1,6 +1,7 @@
use futures::prelude::*;
use irc::client::prelude::*;
use serde::Deserialize;
+use std::str::FromStr;
use log::{debug, info};
use simple_logger::SimpleLogger;
@@ -8,6 +9,7 @@ use simple_logger::SimpleLogger;
const NICK: &'static str = "vortaroboto";
const TROVI_URL: &'static str = "http://www.simplavortaro.org/api/v1/trovi";
const VORTO_URL: &'static str = "http://www.simplavortaro.org/api/v1/vorto";
+const LINEO_SEP: &'static str = "\r\n";
#[derive(Deserialize, Debug)]
struct Vortpartoj {
@@ -56,6 +58,28 @@ struct Vorto {
vorto: String,
}
+enum NumerSelektilo {
+ Cxiuj,
+ Numero(usize),
+}
+
+impl FromStr for NumerSelektilo {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "*" => Ok(Self::Cxiuj),
+ s => Ok(Self::Numero(s.parse::<usize>().map_err(|e| e.to_string())?)),
+ }
+ }
+}
+
+impl Default for NumerSelektilo {
+ fn default() -> Self {
+ Self::Numero(0)
+ }
+}
+
async fn trovu(vorto: &str) -> Result<Vorto, String> {
reqwest::get(format!("{}/{}", VORTO_URL, vorto))
.and_then(|j| j.json::<Vorto>())
@@ -72,13 +96,17 @@ async fn difinu(vorto: &str) -> Result<Trovo, String> {
#[tokio::main]
async fn main() -> irc::error::Result<()> {
-
- SimpleLogger::new().with_level(log::LevelFilter::Debug).init().unwrap();
+ SimpleLogger::new()
+ .with_level(log::LevelFilter::Debug)
+ .init()
+ .unwrap();
let config = Config {
nickname: Some(NICK.to_owned()),
server: Some("irc.libera.chat".to_owned()),
channels: vec!["##esperanto".to_owned()],
+ max_messages_in_burst: Some(5),
+ burst_window_length: Some(1),
..Config::default()
};
@@ -121,6 +149,25 @@ async fn main() -> irc::error::Result<()> {
Ok(())
}
+macro_rules! parse_or_default {
+ ($t:ty, $arg:ident) => {
+ if let Some(s) = $arg.next() {
+ s.parse::<$t>().unwrap_or_default()
+ } else {
+ <$t>::default()
+ }
+ };
+}
+
+macro_rules! wrap_handler {
+ ($f:ident; $w:expr; $($args:expr),+) => {
+ match $f($w, $($args),+).await {
+ Ok(r) => Some(r),
+ Err(e) => Some(format!("Nenio trovata pri: {} ({})", $w, e.to_string())),
+ }
+ };
+}
+
async fn handle_command(cmd: &str) -> Option<String> {
let mut splitted = cmd.split_ascii_whitespace();
match splitted.next() {
@@ -129,40 +176,23 @@ async fn handle_command(cmd: &str) -> Option<String> {
)),
Some("difinu" | "d") => {
if let Some(w) = splitted.next() {
- let index = if let Some(s) = splitted.next() {
- s.parse::<usize>().ok()
- } else {
- None
- };
- match define_word(w, index).await {
- Ok(r) => Some(r),
- Err(e) => Some(format!("Nenio trovata pri: {} ({})", w, e.to_string())),
- }
+ let index = parse_or_default!(NumerSelektilo, splitted);
+ wrap_handler!(define_word; w; index)
} else {
Some(String::from("Uzo: difinu [vorto] [numero]"))
}
}
Some("traduku" | "trad" | "t") => {
if let Some(w) = splitted.next() {
- match traduki(w, splitted.next()).await {
- Ok(r) => Some(r),
- Err(e) => Some(format!("Nenio trovata pri: {} ({})", w, e.to_string())),
- }
+ wrap_handler!(traduki; w; splitted.next())
} else {
Some(String::from("Uzo: traduku [vorto] [lingv'kodo]"))
}
}
Some("vortfarado" | "v" | "vf") => {
if let Some(w) = splitted.next() {
- let index = if let Some(s) = splitted.next() {
- s.parse::<usize>().ok()
- } else {
- None
- };
- match vortfarado(w, index).await {
- Ok(r) => Some(r),
- Err(e) => Some(format!("Nenio trovata pri: {} ({})", w, e.to_string())),
- }
+ let index = parse_or_default!(NumerSelektilo, splitted);
+ wrap_handler!(vortfarado; w; index)
} else {
Some(String::from("Uzo: vortfarado [vorto]"))
}
@@ -172,9 +202,23 @@ async fn handle_command(cmd: &str) -> Option<String> {
}
}
-async fn define_word(vorto: &str, difino: Option<usize>) -> Result<String, String> {
+async fn define_word(vorto: &str, difino: NumerSelektilo) -> Result<String, String> {
let res: Vorto = trovu(vorto).await?;
+ fn format_difino(d: &Difino, index: usize, len: usize, vorto: &str, por: bool) -> String {
+ if por {
+ format!(
+ "Difino {} el {} por {}: {}",
+ index + 1,
+ len,
+ vorto,
+ d.difino
+ )
+ } else {
+ format!("Difino {} el {}: {}", index + 1, len, d.difino)
+ }
+ }
+
if res.difinoj.is_empty() {
return Err(format!("{} ne havas difino.", vorto));
}
@@ -187,17 +231,23 @@ async fn define_word(vorto: &str, difino: Option<usize>) -> Result<String, Strin
}
}
- let index = difino.unwrap_or(1).clamp(1, res.difinoj.len()) - 1;
- if let Some(d) = res.difinoj.get(index) {
- Ok(format!(
- "Difino {} el {} por {}: {}",
- index + 1,
- res.difinoj.len(),
- vorto,
- d.difino
- ))
+ if let NumerSelektilo::Numero(i) = difino {
+ let index = i.clamp(1, res.difinoj.len()) - 1;
+ if let Some(d) = res.difinoj.get(index) {
+ Ok(format_difino(d, index, res.difinoj.len(), vorto, true))
+ } else {
+ unreachable!();
+ }
} else {
- unreachable!();
+ let difj = res
+ .difinoj
+ .iter()
+ .enumerate()
+ .map(|(index, d)| format_difino(d, index, res.difinoj.len(), vorto, false))
+ .collect::<Vec<String>>()
+ .join(LINEO_SEP);
+
+ Ok(format!("Difinoj por {}:\r\n{}", vorto, difj))
}
}
@@ -238,7 +288,7 @@ async fn traduki(vorto: &str, fonto: Option<&str>) -> Result<String, String> {
Ok(tradukoj.join("\r\n"))
}
-async fn vortfarado(vorto: &str, index: Option<usize>) -> Result<String, String> {
+async fn vortfarado(vorto: &str, index: NumerSelektilo) -> Result<String, String> {
let res: Trovo = difinu(vorto).await?;
let vf = res.vortfarado;
@@ -247,11 +297,8 @@ async fn vortfarado(vorto: &str, index: Option<usize>) -> Result<String, String>
return Err(format!("{} ne havas vort'faradon.", vorto));
}
- let index = index.unwrap_or(1).clamp(1, vf.len()) - 1;
-
- if let Some(v) = vf.get(index) {
- let v = v
- .partoj
+ fn make_partoj(v: &Vortfarado) -> String {
+ v.partoj
.iter()
.map(|p| {
if let Some(pv) = &p.vorto {
@@ -261,10 +308,33 @@ async fn vortfarado(vorto: &str, index: Option<usize>) -> Result<String, String>
}
})
.collect::<Vec<String>>()
- .join(" + ");
+ .join(" + ")
+ }
- Ok(format!("Vortfarado {} el {} por \"{}\":\r\n{}", index + 1, vf.len(), vorto, v))
+ if let NumerSelektilo::Numero(i) = index {
+ let index = i.clamp(1, vf.len()) - 1;
+
+ if let Some(v) = vf.get(index) {
+ let v = make_partoj(v);
+ Ok(format!(
+ "Vortfarado {} el {} por \"{}\":\r\n{}",
+ index + 1,
+ vf.len(),
+ vorto,
+ v
+ ))
+ } else {
+ unreachable!();
+ }
} else {
- unreachable!();
+ // Donu cxiuj trancxajxoj
+ let vj = vf.iter().enumerate().map(|(index, v)| {
+ format!(
+ "{}: {}",
+ index + 1,
+ make_partoj(v)
+ )
+ }).collect::<Vec<String>>().join(LINEO_SEP);
+ Ok(format!("Vortfaradoj por \"{}\":\r\n{}", vorto, vj))
}
}