last touches
This commit is contained in:
parent
f1880424ab
commit
7511f3c7d4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
|
config.json
|
||||||
50
Cargo.lock
generated
50
Cargo.lock
generated
@ -492,12 +492,13 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
@ -506,9 +507,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
@ -516,9 +517,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
@ -528,9 +540,9 @@ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -539,21 +551,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -563,7 +575,6 @@ dependencies = [
|
|||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
"memchr",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1189,17 +1200,12 @@ version = "0.2.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "playerbot"
|
name = "playerbot"
|
||||||
version = "0.6.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"futures",
|
||||||
"poise",
|
"poise",
|
||||||
"reqwest 0.13.3",
|
"reqwest 0.13.3",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "playerbot"
|
name = "playerbot"
|
||||||
version = "0.6.1"
|
version = "1.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
|
futures = "0.3.32"
|
||||||
poise = "0.6.2"
|
poise = "0.6.2"
|
||||||
reqwest = {version = "0.13.3", features = ["json"]}
|
reqwest = {version = "0.13.3", features = ["json"]}
|
||||||
serde = {version = "1.0.215", features = ["derive", "serde_derive"]}
|
serde = {version = "1.0.215", features = ["derive", "serde_derive"]}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
"handler_type": "minecraft",
|
"handler_type": "minecraft",
|
||||||
"address": "https://dawn.shibedrill.site",
|
"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,
|
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 crate::{handlers, types::ServerInfo};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::{fs::File, path::Path};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -22,13 +22,15 @@ pub fn parse_configs(path: &Path) -> Result<Config, anyhow::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_handlers(conf: Config) -> Vec<Box<dyn ServerInfo>> {
|
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 {
|
for item in conf.entries {
|
||||||
match item.handler_type.as_str() {
|
match item.handler_type.as_str() {
|
||||||
"minecraft" => {
|
"minecraft" => results.push(Box::new(handlers::minecraft::Server::new(
|
||||||
results.push(Box::new(handlers::minecraft::Server::new(item.token, item.address)))
|
item.token,
|
||||||
},
|
item.address,
|
||||||
_ => {}
|
))),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results
|
results
|
||||||
|
|||||||
@ -84,15 +84,21 @@ impl ServerInfo for Server {
|
|||||||
players_online: players.online,
|
players_online: players.online,
|
||||||
player_limit: players.max,
|
player_limit: players.max,
|
||||||
version: parsed_data.version.unwrap(),
|
version: parsed_data.version.unwrap(),
|
||||||
players: Some(players
|
players: Some(
|
||||||
.list
|
players
|
||||||
.unwrap_or_default()
|
.list
|
||||||
.iter()
|
.unwrap_or_default()
|
||||||
.map(|e| e.name.clone())
|
.iter()
|
||||||
.collect()),
|
.map(|e| e.name.clone())
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
false => ServerResponse::Offline,
|
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 bot_runner;
|
||||||
mod config_parser;
|
mod config_parser;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod types;
|
|
||||||
mod request;
|
mod request;
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
use crate::bot_runner::BotRunner;
|
||||||
|
use futures::{self, future::try_join_all};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
request::request, types::ServerResponse
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
||||||
let config = config_parser::parse_configs(Path::new("config.json")).unwrap();
|
let config = config_parser::parse_configs(Path::new("config.json")).unwrap();
|
||||||
let handlers = config_parser::build_handlers(config);
|
let handlers = config_parser::build_handlers(config);
|
||||||
|
let mut bots: Vec<bot_runner::BotRunner> = vec![];
|
||||||
let http_response = request(handlers[0].api_address()).await.unwrap();
|
for item in handlers {
|
||||||
let results = handlers[0].parse(http_response.text().await.unwrap());
|
bots.push(BotRunner::new(item).await);
|
||||||
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 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 url::Url;
|
||||||
use reqwest::{Response, header::HeaderValue};
|
|
||||||
|
|
||||||
pub async fn request(url: Url) -> Result<Response, reqwest::Error> {
|
pub async fn request(url: Url) -> Result<Response, reqwest::Error> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub enum ServerResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct ServerOnlineResponse {
|
pub struct ServerOnlineResponse {
|
||||||
pub players_online: u64,
|
pub players_online: u64,
|
||||||
pub player_limit: u64,
|
pub player_limit: u64,
|
||||||
@ -19,7 +20,7 @@ pub struct ServerOnlineResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub trait ServerInfo {
|
pub trait ServerInfo: Send + Sync {
|
||||||
fn new(token: String, addr: Url) -> Self
|
fn new(token: String, addr: Url) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
@ -35,4 +36,5 @@ pub trait ServerInfo {
|
|||||||
/// The app token used to send status updates.
|
/// The app token used to send status updates.
|
||||||
fn app_token(&self) -> String;
|
fn app_token(&self) -> String;
|
||||||
|
|
||||||
|
fn supports_playerlist(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user