last touches
This commit is contained in:
parent
f1880424ab
commit
7511f3c7d4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
.env
|
||||
config.json
|
||||
50
Cargo.lock
generated
50
Cargo.lock
generated
@ -492,12 +492,13 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
@ -506,9 +507,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@ -516,9 +517,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
@ -528,9 +540,9 @@ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -539,21 +551,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -563,7 +575,6 @@ dependencies = [
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
@ -1189,17 +1200,12 @@ version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "playerbot"
|
||||
version = "0.6.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
"poise",
|
||||
"reqwest 0.13.3",
|
||||
"serde",
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
[package]
|
||||
name = "playerbot"
|
||||
version = "0.6.1"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.102"
|
||||
futures = "0.3.32"
|
||||
poise = "0.6.2"
|
||||
reqwest = {version = "0.13.3", features = ["json"]}
|
||||
serde = {version = "1.0.215", features = ["derive", "serde_derive"]}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
{
|
||||
"handler_type": "minecraft",
|
||||
"address": "https://dawn.shibedrill.site",
|
||||
"token": "foobar"
|
||||
"token": "MTI5Nzc1NjA3ODE2MjgzNzU0NA.GGjPC_.oy075omzc4IxkX84xc_H7qoYrtil7T0d7ampJ0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,7 +1,135 @@
|
||||
use crate::types::*;
|
||||
use poise;
|
||||
|
||||
struct BotRunner {
|
||||
|
||||
use crate::request::request;
|
||||
use crate::types::*;
|
||||
use poise::serenity_prelude as serenity;
|
||||
use poise::serenity_prelude::{ActivityData, ClientBuilder, GatewayIntents};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub struct BotRunner {
|
||||
client: poise::serenity_prelude::Client,
|
||||
server_data: dyn ServerInfo,
|
||||
}
|
||||
|
||||
pub struct Data {
|
||||
server: Box<dyn ServerInfo>,
|
||||
cached_reply: Mutex<Option<ServerResponse>>,
|
||||
}
|
||||
|
||||
impl BotRunner {
|
||||
pub async fn new(server: Box<dyn ServerInfo>) -> Self {
|
||||
let token = server.app_token();
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands: vec![players(), join()],
|
||||
event_handler: |ctx, event, framework, data| {
|
||||
Box::pin(event_handler(ctx, event, framework, data))
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.setup(|ctx, _ready, framework| {
|
||||
Box::pin(async move {
|
||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||
Ok(Data {
|
||||
server,
|
||||
cached_reply: Mutex::new(None),
|
||||
})
|
||||
})
|
||||
})
|
||||
.build();
|
||||
|
||||
let client = ClientBuilder::new(token, GatewayIntents::non_privileged())
|
||||
.framework(framework)
|
||||
.activity(ActivityData::custom("Waiting on first heartbeat"))
|
||||
.await
|
||||
.unwrap();
|
||||
BotRunner { client }
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<(), serenity::Error> {
|
||||
self.client.start().await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn event_handler(
|
||||
ctx: &serenity::Context,
|
||||
event: &serenity::FullEvent,
|
||||
_framework: poise::FrameworkContext<'_, Data, serenity::Error>,
|
||||
data: &Data,
|
||||
) -> Result<(), serenity::Error> {
|
||||
match event {
|
||||
serenity::FullEvent::Ready {
|
||||
data_about_bot: _bot_data,
|
||||
} => loop {
|
||||
println!("Checking status: {}", data.server.api_address());
|
||||
let http_response = request(data.server.api_address()).await.unwrap();
|
||||
let results = data.server.parse(http_response.text().await.unwrap());
|
||||
match &results {
|
||||
ServerResponse::Offline => {
|
||||
ctx.set_presence(
|
||||
Some(ActivityData::custom("Server offline!")),
|
||||
serenity::OnlineStatus::DoNotDisturb,
|
||||
);
|
||||
}
|
||||
ServerResponse::Online(online_info) => {
|
||||
ctx.set_presence(
|
||||
Some(ActivityData::custom(format!(
|
||||
"{}/{} online, v{}",
|
||||
online_info.players_online,
|
||||
online_info.player_limit,
|
||||
online_info.version
|
||||
))),
|
||||
if online_info.players_online > 0 {
|
||||
serenity::OnlineStatus::Online
|
||||
} else {
|
||||
serenity::OnlineStatus::Idle
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
//println!("{:#?}", &results);
|
||||
*data.cached_reply.lock().await = Some(results);
|
||||
tokio::time::sleep(std::time::Duration::from_secs(30)).await;
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[poise::command(slash_command)]
|
||||
pub async fn players(
|
||||
ctx: poise::Context<'_, Data, serenity::Error>,
|
||||
) -> Result<(), serenity::Error> {
|
||||
if let Some(reply) = &*ctx.data().cached_reply.lock().await {
|
||||
match reply {
|
||||
ServerResponse::Offline => ctx.say("Server is offline!").await?,
|
||||
ServerResponse::Online(on) => {
|
||||
if let Some(list) = &on.players {
|
||||
ctx.say(format!(
|
||||
"{} out of {} players are online.\nPlayers online: {}",
|
||||
on.players_online,
|
||||
on.player_limit,
|
||||
list.join(", ")
|
||||
))
|
||||
.await?
|
||||
} else {
|
||||
ctx.say(format!(
|
||||
"{} out of {} players are online.",
|
||||
on.players_online, on.player_limit
|
||||
))
|
||||
.await?
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
ctx.say("No status response yet. Please wait 30 seconds.")
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(slash_command)]
|
||||
pub async fn join(
|
||||
ctx: poise::Context<'_, Data, serenity::Error>,
|
||||
) -> Result<(), serenity::Error> {
|
||||
ctx.say(format!("To join, type `{}` in the server URL box or search bar.", ctx.data().server.addressable_name())).await?;
|
||||
Ok(())
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{fs::File, path::Path};
|
||||
use crate::{handlers, types::ServerInfo};
|
||||
use serde::Deserialize;
|
||||
use std::{fs::File, path::Path};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -22,12 +22,14 @@ pub fn parse_configs(path: &Path) -> Result<Config, anyhow::Error> {
|
||||
}
|
||||
|
||||
pub fn build_handlers(conf: Config) -> Vec<Box<dyn ServerInfo>> {
|
||||
let mut results: Vec<Box<dyn ServerInfo>> = vec!();
|
||||
assert_eq!(conf.version, "0.1.0");
|
||||
let mut results: Vec<Box<dyn ServerInfo>> = vec![];
|
||||
for item in conf.entries {
|
||||
match item.handler_type.as_str() {
|
||||
"minecraft" => {
|
||||
results.push(Box::new(handlers::minecraft::Server::new(item.token, item.address)))
|
||||
},
|
||||
"minecraft" => results.push(Box::new(handlers::minecraft::Server::new(
|
||||
item.token,
|
||||
item.address,
|
||||
))),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,15 +84,21 @@ impl ServerInfo for Server {
|
||||
players_online: players.online,
|
||||
player_limit: players.max,
|
||||
version: parsed_data.version.unwrap(),
|
||||
players: Some(players
|
||||
players: Some(
|
||||
players
|
||||
.list
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|e| e.name.clone())
|
||||
.collect()),
|
||||
.collect(),
|
||||
),
|
||||
})
|
||||
}
|
||||
false => ServerResponse::Offline,
|
||||
}
|
||||
}
|
||||
|
||||
fn supports_playerlist(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
31
src/main.rs
31
src/main.rs
@ -1,35 +1,22 @@
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
mod bot_runner;
|
||||
mod config_parser;
|
||||
mod handlers;
|
||||
mod types;
|
||||
mod request;
|
||||
mod types;
|
||||
|
||||
use crate::bot_runner::BotRunner;
|
||||
use futures::{self, future::try_join_all};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{
|
||||
request::request, types::ServerResponse
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
let config = config_parser::parse_configs(Path::new("config.json")).unwrap();
|
||||
let handlers = config_parser::build_handlers(config);
|
||||
|
||||
let http_response = request(handlers[0].api_address()).await.unwrap();
|
||||
let results = handlers[0].parse(http_response.text().await.unwrap());
|
||||
match results {
|
||||
ServerResponse::Offline => println!("Offline"),
|
||||
ServerResponse::Online(online_info) => {
|
||||
println!(
|
||||
"Name: {}\nAddress: {}\nVersion: {}\nPlayers: {}/{}",
|
||||
online_info.readable_name,
|
||||
online_info.searchable_name,
|
||||
online_info.version,
|
||||
online_info.players_online,
|
||||
online_info.player_limit
|
||||
);
|
||||
println!("Players online: {}", online_info.players.unwrap().join(", "));
|
||||
}
|
||||
let mut bots: Vec<bot_runner::BotRunner> = vec![];
|
||||
for item in handlers {
|
||||
bots.push(BotRunner::new(item).await);
|
||||
}
|
||||
let futures: Vec<_> = bots.iter_mut().map(|b| b.run()).collect();
|
||||
let _ = try_join_all(futures).await;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use reqwest::{header::HeaderValue, Response};
|
||||
use url::Url;
|
||||
use reqwest::{Response, header::HeaderValue};
|
||||
|
||||
pub async fn request(url: Url) -> Result<Response, reqwest::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
@ -7,6 +7,7 @@ pub enum ServerResponse {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct ServerOnlineResponse {
|
||||
pub players_online: u64,
|
||||
pub player_limit: u64,
|
||||
@ -19,7 +20,7 @@ pub struct ServerOnlineResponse {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait ServerInfo {
|
||||
pub trait ServerInfo: Send + Sync {
|
||||
fn new(token: String, addr: Url) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
@ -35,4 +36,5 @@ pub trait ServerInfo {
|
||||
/// The app token used to send status updates.
|
||||
fn app_token(&self) -> String;
|
||||
|
||||
fn supports_playerlist(&self) -> bool;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user