mirror of
https://codeberg.org/spire/dispenser.git
synced 2026-06-03 10:04:07 +02:00
keep server alive if it has players
This commit is contained in:
parent
105745a61a
commit
da2b13feb1
4 changed files with 169 additions and 153 deletions
151
Cargo.lock
generated
151
Cargo.lock
generated
|
|
@ -221,12 +221,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cron"
|
name = "cron"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "628a3464535cee4e75af89e8c293bab926deaddfa166553b75029066c846be3f"
|
checksum = "e009ed0b762cf7a967a34dfdc67d5967d3f828f12901d37081432c3dd1668f8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"nom",
|
"nom",
|
||||||
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -300,16 +301,17 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"camino",
|
"camino",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"cron",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"petname",
|
"petname",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
"rcon",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"thrussh",
|
"thrussh",
|
||||||
"thrussh-keys",
|
"thrussh-keys",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-cron-scheduler",
|
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -341,6 +343,20 @@ dependencies = [
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "err-derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcc7f65832b62ed38939f98966824eb6294911c3629b0e9a262bfb80836d9686"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
|
@ -631,15 +647,6 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|
@ -694,15 +701,6 @@ dependencies = [
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
|
||||||
dependencies = [
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
|
|
@ -838,31 +836,6 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
|
||||||
dependencies = [
|
|
||||||
"instant",
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"instant",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "password-hash"
|
name = "password-hash"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -938,6 +911,30 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.19"
|
version = "0.5.19"
|
||||||
|
|
@ -1014,6 +1011,16 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rcon"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d982f524250f15117766c710229add75d47c54c9ef654b8c7b5a4da49058750"
|
||||||
|
dependencies = [
|
||||||
|
"err-derive",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
|
@ -1114,6 +1121,12 @@ dependencies = [
|
||||||
"webpki",
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
@ -1129,12 +1142,6 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sct"
|
name = "sct"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
|
@ -1216,12 +1223,6 @@ version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
@ -1255,6 +1256,18 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synstructure"
|
||||||
|
version = "0.12.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
|
@ -1398,25 +1411,12 @@ dependencies = [
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-cron-scheduler"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6af42ec81010dbf80a8762206e4cf5273ef291b91f203b48e250130ca4289392"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"cron",
|
|
||||||
"tokio",
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
@ -1559,15 +1559,6 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uuid"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,12 @@ thiserror = "1"
|
||||||
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
|
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
|
||||||
camino = "1"
|
camino = "1"
|
||||||
petname = "1"
|
petname = "1"
|
||||||
thrussh = "0.33"
|
thrussh = "0.33"
|
||||||
thrussh-keys = "0.21"
|
thrussh-keys = "0.21"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
tokio-cron-scheduler = "0.2"
|
cron = "0.9"
|
||||||
|
rcon = "0.4"
|
||||||
148
src/main.rs
148
src/main.rs
|
|
@ -1,19 +1,24 @@
|
||||||
use crate::cloud::{Cloud, CloudError};
|
use crate::cloud::{Cloud, CloudError, Server};
|
||||||
use crate::config::{Config, ConfigError, ServerConfig};
|
use crate::config::{Config, ConfigError, ServerConfig};
|
||||||
use crate::dns::{DynDnsClient, DynDnsError};
|
use crate::dns::{DynDnsClient, DynDnsError};
|
||||||
|
use crate::rcon::Rcon;
|
||||||
use crate::ssh::SshError;
|
use crate::ssh::SshError;
|
||||||
|
use chrono::Utc;
|
||||||
|
use cron::Schedule;
|
||||||
use ssh::SshSession;
|
use ssh::SshSession;
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::task::{spawn, JoinError};
|
use tokio::select;
|
||||||
|
use tokio::signal::ctrl_c;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use tokio_cron_scheduler::{Job, JobScheduler};
|
|
||||||
|
|
||||||
mod cloud;
|
mod cloud;
|
||||||
mod config;
|
mod config;
|
||||||
mod dns;
|
mod dns;
|
||||||
|
mod rcon;
|
||||||
mod ssh;
|
mod ssh;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
@ -31,25 +36,9 @@ pub enum Error {
|
||||||
#[error("Already running")]
|
#[error("Already running")]
|
||||||
AlreadyRunning,
|
AlreadyRunning,
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Schedule(ScheduleError),
|
Schedule(#[from] cron::error::Error),
|
||||||
}
|
#[error("{0}")]
|
||||||
|
Rcon(#[from] ::rcon::Error),
|
||||||
#[derive(Debug, Error)]
|
|
||||||
#[error("{0}")]
|
|
||||||
pub struct ScheduleError(ScheduleErrorImpl);
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
enum ScheduleErrorImpl {
|
|
||||||
#[error("Error setting up schedule")]
|
|
||||||
Schedule(String),
|
|
||||||
#[error("Error running schedule")]
|
|
||||||
Join(JoinError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ScheduleErrorImpl> for Error {
|
|
||||||
fn from(e: ScheduleErrorImpl) -> Self {
|
|
||||||
Error::Schedule(ScheduleError(e))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup(ssh: &mut SshSession, config: &ServerConfig) -> Result<(), Error> {
|
async fn setup(ssh: &mut SshSession, config: &ServerConfig) -> Result<(), Error> {
|
||||||
|
|
@ -124,65 +113,80 @@ async fn main() -> Result<(), Error> {
|
||||||
};
|
};
|
||||||
let cloud = config.cloud()?;
|
let cloud = config.cloud()?;
|
||||||
|
|
||||||
let mut sched = JobScheduler::new();
|
let start_schedule = Schedule::from_str(&config.schedule.start)?;
|
||||||
|
let stop_schedule = Schedule::from_str(&config.schedule.stop)?;
|
||||||
|
|
||||||
let server_id: Arc<Mutex<Option<String>>> = Arc::default();
|
select! {
|
||||||
|
_ = run_loop(cloud, config, start_schedule, stop_schedule) => {},
|
||||||
sched
|
_ = ctrl_c() => {},
|
||||||
.add(stop_job(cloud.clone(), &config, server_id.clone()))
|
}
|
||||||
.map_err(|e| ScheduleErrorImpl::Schedule(format!("{:#}", e)))?;
|
|
||||||
sched
|
|
||||||
.add(start_job(cloud, config, server_id))
|
|
||||||
.map_err(|e| ScheduleErrorImpl::Schedule(format!("{:#}", e)))?;
|
|
||||||
|
|
||||||
sched.start().await.map_err(ScheduleErrorImpl::Join)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_job(cloud: Arc<dyn Cloud>, config: &Config, server_id: Arc<Mutex<Option<String>>>) -> Job {
|
async fn run_loop(
|
||||||
Job::new(&config.schedule.stop, move |_uuid, _l| {
|
cloud: Arc<dyn Cloud>,
|
||||||
let server_id = server_id.clone();
|
config: Config,
|
||||||
let cloud = cloud.clone();
|
start_schedule: Schedule,
|
||||||
spawn(async move {
|
stop_schedule: Schedule,
|
||||||
let id = server_id.lock().unwrap().take();
|
) {
|
||||||
if let Some(id) = id {
|
let mut active_server: Option<Server> = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let next_start = start_schedule.upcoming(Utc).next().unwrap();
|
||||||
|
let next_stop = stop_schedule.upcoming(Utc).next().unwrap();
|
||||||
|
|
||||||
|
// we're between start time and stop time
|
||||||
|
if active_server.is_none() && next_start > next_stop {
|
||||||
|
println!("Starting server");
|
||||||
|
match start(cloud.as_ref(), &config).await {
|
||||||
|
Ok(server) => active_server = Some(server),
|
||||||
|
Err(e) => eprintln!("{:#}", e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're between stop time and start time
|
||||||
|
if active_server.is_some() && next_stop > next_start {
|
||||||
|
let active_players_res = match Rcon::new(
|
||||||
|
(active_server.as_ref().unwrap().ip, 27015),
|
||||||
|
&config.server.rcon,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(mut rcon) => rcon.player_count().await,
|
||||||
|
Err(e) => Err(e),
|
||||||
|
};
|
||||||
|
let stop = match active_players_res {
|
||||||
|
Ok(0) => true,
|
||||||
|
Ok(count) => {
|
||||||
|
println!(
|
||||||
|
"Want to stop server, but there are still {} active players",
|
||||||
|
count
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if stop {
|
||||||
|
let id = &active_server.as_ref().unwrap().id;
|
||||||
println!("Stopping server {}", id);
|
println!("Stopping server {}", id);
|
||||||
match cloud.kill(&id).await {
|
match cloud.kill(&id).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {
|
||||||
|
active_server = None;
|
||||||
|
}
|
||||||
Err(e) => eprintln!("{:#}", e),
|
Err(e) => eprintln!("{:#}", e),
|
||||||
};
|
}
|
||||||
} else {
|
}
|
||||||
println!("No server to stop")
|
}
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(60)).await;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_job(cloud: Arc<dyn Cloud>, config: Config, server_id: Arc<Mutex<Option<String>>>) -> Job {
|
async fn start(cloud: &dyn Cloud, config: &Config) -> Result<Server, Error> {
|
||||||
let schedule = config.schedule.start.clone();
|
|
||||||
let config = Arc::new(config);
|
|
||||||
Job::new(&schedule, move |_uuid, _l| {
|
|
||||||
let cloud = cloud.clone();
|
|
||||||
let config = config.clone();
|
|
||||||
let server_id = server_id.clone();
|
|
||||||
spawn(async move {
|
|
||||||
let cloud = cloud.as_ref();
|
|
||||||
let already_started = { server_id.lock().unwrap().is_some() };
|
|
||||||
if !already_started {
|
|
||||||
println!("Starting server");
|
|
||||||
match start(cloud, &config).await {
|
|
||||||
Ok(id) => *server_id.lock().unwrap() = Some(id),
|
|
||||||
Err(e) => eprintln!("{:#}", e),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start(cloud: &dyn Cloud, config: &Config) -> Result<String, Error> {
|
|
||||||
let list = cloud.list().await?;
|
let list = cloud.list().await?;
|
||||||
if !list.is_empty() {
|
if !list.is_empty() {
|
||||||
return Err(Error::AlreadyRunning);
|
return Err(Error::AlreadyRunning);
|
||||||
|
|
@ -227,5 +231,5 @@ async fn start(cloud: &dyn Cloud, config: &Config) -> Result<String, Error> {
|
||||||
" connect {}; password {}",
|
" connect {}; password {}",
|
||||||
connect_host, config.server.password
|
connect_host, config.server.password
|
||||||
);
|
);
|
||||||
Ok(server.id)
|
Ok(server)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/rcon.rs
Normal file
20
src/rcon.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use crate::Error;
|
||||||
|
use rcon::Connection;
|
||||||
|
use tokio::net::ToSocketAddrs;
|
||||||
|
|
||||||
|
pub struct Rcon(Connection);
|
||||||
|
|
||||||
|
impl Rcon {
|
||||||
|
pub async fn new<A: ToSocketAddrs>(host: A, password: &str) -> Result<Self, Error> {
|
||||||
|
Ok(Rcon(Connection::builder().connect(host, password).await?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn player_count(&mut self) -> Result<usize, Error> {
|
||||||
|
let status = self.0.cmd("status").await?;
|
||||||
|
let player_lines = status
|
||||||
|
.lines()
|
||||||
|
.filter(|line| line.starts_with('#'))
|
||||||
|
.filter(|line| !line.contains(" BOT "));
|
||||||
|
Ok(player_lines.count())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue