html terminal
Diffstat (limited to 'src/bot/player.rs')
-rw-r--r--src/bot/player.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/bot/player.rs b/src/bot/player.rs
new file mode 100644
index 0000000..590f9e4
--- /dev/null
+++ b/src/bot/player.rs
@@ -0,0 +1,85 @@
+use super::{get_nextblock, strip_colors, Context};
+use crate::send;
+use anyhow::Result;
+use futures_util::StreamExt;
+use std::net::Ipv4Addr;
+use std::str::FromStr;
+use std::time::Instant;
+use tokio::sync::{broadcast, MappedMutexGuard, Mutex, MutexGuard};
+
+#[derive(Clone, Debug)]
+pub struct Player {
+ pub admin: bool,
+ pub name: String,
+ pub uuid: String,
+ pub ip: Ipv4Addr,
+}
+
+static PLAYERS: Mutex<(Vec<Player>, Option<Instant>)> = Mutex::const_new((vec![], None));
+
+async fn update(
+ stdin: &broadcast::Sender<String>,
+) -> Result<MutexGuard<(Vec<Player>, Option<Instant>)>> {
+ let mut lock = PLAYERS.lock().await;
+ if lock.1.is_none() || lock.1.unwrap().elapsed().as_millis() > 500 {
+ lock.0 = get_players(stdin).await?;
+ lock.1 = Some(Instant::now());
+ }
+ Ok(lock)
+}
+pub struct Players {}
+impl Players {
+ pub async fn get_all(
+ stdin: &broadcast::Sender<String>,
+ ) -> Result<MappedMutexGuard<Vec<Player>>> {
+ {
+ Ok(MutexGuard::map(update(stdin).await?, |(p, _)| p))
+ }
+ }
+
+ pub async fn find(
+ stdin: &broadcast::Sender<String>,
+ name: String,
+ ) -> Result<Option<MappedMutexGuard<Player>>> {
+ Ok(MutexGuard::try_map(update(stdin).await?, |(p, _)| {
+ p.iter_mut().find(|x| x.name == name)
+ })
+ .ok())
+ }
+}
+
+async fn get_players(stdin: &broadcast::Sender<String>) -> Result<Vec<Player>> {
+ let mut players = vec![];
+ send!(stdin, "players")?;
+ let recv = get_nextblock().await;
+ for line in recv.lines() {
+ if line.starts_with("No") {
+ break;
+ } else if line.is_empty() {
+ continue;
+ }
+ let split = line.split('/').collect::<Vec<&str>>();
+ if split.len() != 3 {
+ continue;
+ }
+ if let Some((admin, name)) = split[0].split_once(' ') {
+ players.push(Player {
+ admin: admin == "[A]",
+ name: strip_colors(name),
+ uuid: split[1].to_owned(),
+ ip: Ipv4Addr::from_str(split[2]).unwrap(),
+ })
+ }
+ }
+ Ok(players)
+}
+
+pub async fn autocomplete<'a>(
+ ctx: Context<'a>,
+ partial: &'a str,
+) -> impl futures::Stream<Item = String> + 'a {
+ let x = Players::get_all(&ctx.data().stdin).await.unwrap().clone();
+ futures::stream::iter(x)
+ .filter(move |p| futures::future::ready(p.name.starts_with(partial)))
+ .map(|p| p.name)
+}