generated from PlexSheep/rs-base
feat: launch many services somewhat at once
This commit is contained in:
parent
f945eea904
commit
ea23e93ec9
|
@ -8,7 +8,7 @@ use libpt::log::warn;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use super::{Challenge, ChallengeDesc};
|
use super::{ChallengeDesc, ChallengeLike};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::has_won;
|
use crate::has_won;
|
||||||
use crate::vault::VaultRef;
|
use crate::vault::VaultRef;
|
||||||
|
@ -21,7 +21,7 @@ pub struct C1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Challenge for C1 {
|
impl ChallengeLike for C1 {
|
||||||
fn config(&self) -> Config {
|
fn config(&self) -> Config {
|
||||||
self.config.clone()
|
self.config.clone()
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ impl Challenge for C1 {
|
||||||
|
|
||||||
fn text() -> ChallengeDesc {
|
fn text() -> ChallengeDesc {
|
||||||
ChallengeDesc {
|
ChallengeDesc {
|
||||||
|
id: 1,
|
||||||
title: "dumb TCP".to_string(),
|
title: "dumb TCP".to_string(),
|
||||||
hints: vec![String::from("TCP connect to 1337.")],
|
hints: vec![String::from("TCP connect to 1337.")],
|
||||||
solution: String::from("Connect by TCP, then the secret will be sent to you."),
|
solution: String::from("Connect by TCP, then the secret will be sent to you."),
|
||||||
|
|
|
@ -10,7 +10,7 @@ use libpt::log::{info, warn};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
use super::{Challenge, ChallengeDesc};
|
use super::{ChallengeDesc, ChallengeLike};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::has_won;
|
use crate::has_won;
|
||||||
use crate::vault::VaultRef;
|
use crate::vault::VaultRef;
|
||||||
|
@ -47,7 +47,7 @@ impl C2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Challenge for C2 {
|
impl ChallengeLike for C2 {
|
||||||
fn config(&self) -> Config {
|
fn config(&self) -> Config {
|
||||||
self.config.clone()
|
self.config.clone()
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ impl Challenge for C2 {
|
||||||
}
|
}
|
||||||
fn text() -> ChallengeDesc {
|
fn text() -> ChallengeDesc {
|
||||||
ChallengeDesc {
|
ChallengeDesc {
|
||||||
|
id: 2,
|
||||||
title: "TCP dialogue".to_string(),
|
title: "TCP dialogue".to_string(),
|
||||||
hints: vec![String::from(
|
hints: vec![String::from(
|
||||||
"TCP connect to 1337 and give me a special u16",
|
"TCP connect to 1337 and give me a special u16",
|
||||||
|
|
|
@ -29,7 +29,7 @@ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use super::{Challenge, ChallengeDesc};
|
use super::{ChallengeDesc, ChallengeLike};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::has_won;
|
use crate::has_won;
|
||||||
use crate::vault::VaultRef;
|
use crate::vault::VaultRef;
|
||||||
|
@ -207,7 +207,7 @@ impl C3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Challenge for C3 {
|
impl ChallengeLike for C3 {
|
||||||
fn config(&self) -> Config {
|
fn config(&self) -> Config {
|
||||||
self.config.clone()
|
self.config.clone()
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,7 @@ impl Challenge for C3 {
|
||||||
}
|
}
|
||||||
fn text() -> ChallengeDesc {
|
fn text() -> ChallengeDesc {
|
||||||
ChallengeDesc {
|
ChallengeDesc {
|
||||||
|
id: 3,
|
||||||
title: "TCP math exam".to_string(),
|
title: "TCP math exam".to_string(),
|
||||||
hints: vec![
|
hints: vec![
|
||||||
"TCP connect to 1337 and answer the questions.".to_string(),
|
"TCP connect to 1337 and answer the questions.".to_string(),
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub mod c3;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ChallengeDesc {
|
pub struct ChallengeDesc {
|
||||||
|
id: usize,
|
||||||
title: String,
|
title: String,
|
||||||
hints: Vec<String>,
|
hints: Vec<String>,
|
||||||
solution: String,
|
solution: String,
|
||||||
|
@ -30,7 +31,7 @@ impl ChallengeDesc {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A vector of strings containing hints for the challenge.
|
/// A [`Vec<String>`] containing hints for the challenge.
|
||||||
pub fn hints(&self) -> Vec<&str> {
|
pub fn hints(&self) -> Vec<&str> {
|
||||||
self.hints.iter().map(|a| a.as_ref()).collect()
|
self.hints.iter().map(|a| a.as_ref()).collect()
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ impl ChallengeDesc {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A string containing the solution to the challenge.
|
/// A [`String`] containing the solution to the challenge.
|
||||||
pub fn solution(&self) -> &str {
|
pub fn solution(&self) -> &str {
|
||||||
&self.solution
|
&self.solution
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,7 @@ impl ChallengeDesc {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A string containing the description to the challenge.
|
/// A [`String`] containing the description to the challenge.
|
||||||
pub fn description(&self) -> &str {
|
pub fn description(&self) -> &str {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
@ -62,17 +63,27 @@ impl ChallengeDesc {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A string containing the title to the challenge.
|
/// A [`String`] containing the title to the challenge.
|
||||||
pub fn title(&self) -> &str {
|
pub fn title(&self) -> &str {
|
||||||
&self.title
|
&self.title
|
||||||
}
|
}
|
||||||
|
/// Returns the id to the challenge.
|
||||||
|
///
|
||||||
|
/// The id is just the index of the challenge to distinguish them easily
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A [`usize`] containing the title to the challenge.
|
||||||
|
pub fn id(&self) -> usize {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the behavior of a challenge.
|
/// Defines the behavior of a challenge.
|
||||||
///
|
///
|
||||||
/// Any type that implements this trait can be served as a challenge in the Wooly Vault application.
|
/// Any type that implements this trait can be served as a challenge in the Wooly Vault application.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Challenge
|
pub trait ChallengeLike
|
||||||
where
|
where
|
||||||
Self: Sized + 'static,
|
Self: Sized + 'static,
|
||||||
Self: Send,
|
Self: Send,
|
||||||
|
@ -127,6 +138,7 @@ where
|
||||||
async fn start(&self) -> anyhow::Result<()> {
|
async fn start(&self) -> anyhow::Result<()> {
|
||||||
let c = self.clone();
|
let c = self.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
info!("starting C{}", Self::text().id());
|
||||||
if let Err(e) = c.serve().await {
|
if let Err(e) = c.serve().await {
|
||||||
error!("challenge {} has crashed! {e:#?}", Self::text().title());
|
error!("challenge {} has crashed! {e:#?}", Self::text().title());
|
||||||
};
|
};
|
||||||
|
@ -134,34 +146,3 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selects a challenge by index and serves it with the given configuration and vault.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `index` - The index of the challenge to select.
|
|
||||||
/// * `config` - The configuration for the challenge.
|
|
||||||
/// * `vault` - The vault that holds the secret for the challenge.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A result indicating whether the challenge has successfully ended.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Returns an error if no challenge with the given index exists, or if the challenge that is being
|
|
||||||
/// served errors.
|
|
||||||
pub async fn select_and_start(index: u16, config: Config, vault: VaultRef) -> anyhow::Result<()> {
|
|
||||||
info!("select+start");
|
|
||||||
match index {
|
|
||||||
1 => c1::C1::new(config, vault).start().await?,
|
|
||||||
2 => c2::C2::new(config, vault).start().await?,
|
|
||||||
3 => c3::C3::new(config, vault).start().await?,
|
|
||||||
_ => {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"no challenge with index {index} does currently exist"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
64
src/lib.rs
64
src/lib.rs
|
@ -14,6 +14,12 @@
|
||||||
//! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at
|
//! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at
|
||||||
//! once if needed.
|
//! once if needed.
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use libpt::log::info;
|
||||||
|
|
||||||
|
use self::challenge::ChallengeLike;
|
||||||
|
use self::config::Config;
|
||||||
|
use self::meta::Service;
|
||||||
use self::vault::VaultRef;
|
use self::vault::VaultRef;
|
||||||
|
|
||||||
pub mod challenge;
|
pub mod challenge;
|
||||||
|
@ -31,3 +37,61 @@ pub(crate) async fn has_won(
|
||||||
vault.add_winner(contestant.clone()).await;
|
vault.add_winner(contestant.clone()).await;
|
||||||
libpt::log::info!("Sending the secret to {addr}")
|
libpt::log::info!("Sending the secret to {addr}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects a single challenge by index and serves it with the given configuration and vault.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `index` - The index of the challenge to select.
|
||||||
|
/// * `config` - The configuration for the challenge.
|
||||||
|
/// * `vault` - The vault that holds the secret for the challenge.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A result indicating whether the challenge has successfully ended.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if no challenge with the given index exists, or if the challenge that is being
|
||||||
|
/// served errors.
|
||||||
|
pub async fn select_and_start_single(
|
||||||
|
index: u16,
|
||||||
|
config: Config,
|
||||||
|
vault: VaultRef,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
info!("select+start");
|
||||||
|
match index {
|
||||||
|
1 => challenge::c1::C1::new(config, vault).start().await?,
|
||||||
|
2 => challenge::c2::C2::new(config, vault).start().await?,
|
||||||
|
3 => challenge::c3::C3::new(config, vault).start().await?,
|
||||||
|
_ => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"no challenge with index {index} does currently exist"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_all(config: Config, vault: VaultRef) -> anyhow::Result<()> {
|
||||||
|
let c1 = challenge::c1::C1::new(config.clone(), vault.clone());
|
||||||
|
let c2 = challenge::c2::C2::new(config.clone(), vault.clone());
|
||||||
|
let c3 = challenge::c3::C3::new(config.clone(), vault.clone());
|
||||||
|
|
||||||
|
c1.start().await?;
|
||||||
|
c2.start().await?;
|
||||||
|
c3.start().await?;
|
||||||
|
|
||||||
|
meta::serve(
|
||||||
|
vec![
|
||||||
|
challenge::c1::C1::text(),
|
||||||
|
challenge::c2::C2::text(),
|
||||||
|
challenge::c3::C3::text(),
|
||||||
|
],
|
||||||
|
vault.clone(),
|
||||||
|
config.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use libpt::log::{debug, info};
|
use libpt::log::{debug, info};
|
||||||
|
|
||||||
use wooly_vault::{challenge::select_and_start, config::Config, vault::Vault};
|
use wooly_vault::{config::Config, vault::Vault};
|
||||||
|
use wooly_vault::{select_and_start_single, start_all};
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
@ -21,7 +22,7 @@ async fn main() -> Result<()> {
|
||||||
let secret = Config::secret()?;
|
let secret = Config::secret()?;
|
||||||
let v = Vault::new(&secret);
|
let v = Vault::new(&secret);
|
||||||
|
|
||||||
select_and_start(conf.challenge, conf, v).await?;
|
start_all(conf, v).await?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await
|
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await
|
||||||
|
|
|
@ -26,27 +26,21 @@ pub struct Service<'tp> {
|
||||||
challenges: Vec<ChallengeDesc>,
|
challenges: Vec<ChallengeDesc>,
|
||||||
}
|
}
|
||||||
impl<'tp> Service<'tp> {
|
impl<'tp> Service<'tp> {
|
||||||
fn new(
|
fn build(vault: VaultRef, config: Config, challenges: Vec<ChallengeDesc>) -> Result<Arc<Self>> {
|
||||||
vault: VaultRef,
|
let mut env = Environment::new();
|
||||||
config: Config,
|
env.add_template("index", include_str!("../../data/www/admin.html"))?;
|
||||||
env: Environment<'tp>,
|
Ok(Self {
|
||||||
challenges: Vec<ChallengeDesc>,
|
|
||||||
) -> Arc<Self> {
|
|
||||||
Self {
|
|
||||||
vault,
|
vault,
|
||||||
config,
|
config,
|
||||||
env,
|
env,
|
||||||
challenges,
|
challenges,
|
||||||
}
|
}
|
||||||
.into()
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serve(challenges: Vec<ChallengeDesc>, vault: VaultRef, config: Config) -> Result<()> {
|
pub async fn serve(challenges: Vec<ChallengeDesc>, vault: VaultRef, config: Config) -> Result<()> {
|
||||||
let mut env = Environment::new();
|
let service = Service::build(vault, config, challenges)?;
|
||||||
env.add_template("index", include_str!("../../data/www/admin.html"))?;
|
|
||||||
|
|
||||||
let service = Service::new(vault, config, env, challenges);
|
|
||||||
|
|
||||||
let routes = Service::admin_routes(service.clone())
|
let routes = Service::admin_routes(service.clone())
|
||||||
.or(Service::ressources_routes())
|
.or(Service::ressources_routes())
|
||||||
|
|
Loading…
Reference in New Issue