81 lines
2.2 KiB
Rust
81 lines
2.2 KiB
Rust
use anyhow::Result;
|
|
use tracing::info;
|
|
use super::rcon::RconClient;
|
|
|
|
/// Player information from an ARK RCON `ListPlayers` response.
|
|
pub struct ArkPlayer {
|
|
pub name: String,
|
|
pub steamid: String,
|
|
}
|
|
|
|
/// Query an ARK server for its connected players.
|
|
pub async fn get_players(rcon_address: &str, rcon_password: &str) -> Result<Vec<ArkPlayer>> {
|
|
let mut client = RconClient::connect(rcon_address, rcon_password).await?;
|
|
let response = client.command("ListPlayers").await?;
|
|
|
|
let players = parse_list_players_response(&response);
|
|
info!(count = players.len(), "ARK player list retrieved");
|
|
|
|
Ok(players)
|
|
}
|
|
|
|
/// Parses lines shaped like `0. PlayerName, 76561198000000000`.
|
|
fn parse_list_players_response(response: &str) -> Vec<ArkPlayer> {
|
|
let mut players = Vec::new();
|
|
|
|
for line in response.lines() {
|
|
let trimmed = line.trim();
|
|
if trimmed.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
// "No Players Connected"
|
|
if trimmed.eq_ignore_ascii_case("no players connected") {
|
|
break;
|
|
}
|
|
|
|
// Strip the "<index>. " prefix.
|
|
let entry = match trimmed.split_once('.') {
|
|
Some((index, rest)) if index.trim().chars().all(|c| c.is_ascii_digit()) => rest.trim(),
|
|
_ => continue,
|
|
};
|
|
|
|
let (name, steamid) = match entry.rsplit_once(',') {
|
|
Some((name, steamid)) => (name.trim(), steamid.trim()),
|
|
None => (entry, ""),
|
|
};
|
|
|
|
if name.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
players.push(ArkPlayer {
|
|
name: name.to_string(),
|
|
steamid: steamid.to_string(),
|
|
});
|
|
}
|
|
|
|
players
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn parses_connected_players() {
|
|
let response = "0. Alper, 76561198000000001\n1. Rezan, 76561198000000002\n";
|
|
let players = parse_list_players_response(response);
|
|
|
|
assert_eq!(players.len(), 2);
|
|
assert_eq!(players[0].name, "Alper");
|
|
assert_eq!(players[0].steamid, "76561198000000001");
|
|
assert_eq!(players[1].name, "Rezan");
|
|
}
|
|
|
|
#[test]
|
|
fn handles_empty_server() {
|
|
assert!(parse_list_players_response("No Players Connected\n").is_empty());
|
|
}
|
|
}
|