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::net::TcpListener;
|
||||
|
||||
use super::{Challenge, ChallengeDesc};
|
||||
use super::{ChallengeDesc, ChallengeLike};
|
||||
use crate::config::Config;
|
||||
use crate::has_won;
|
||||
use crate::vault::VaultRef;
|
||||
|
@ -21,7 +21,7 @@ pub struct C1 {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Challenge for C1 {
|
||||
impl ChallengeLike for C1 {
|
||||
fn config(&self) -> Config {
|
||||
self.config.clone()
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ impl Challenge for C1 {
|
|||
|
||||
fn text() -> ChallengeDesc {
|
||||
ChallengeDesc {
|
||||
id: 1,
|
||||
title: "dumb TCP".to_string(),
|
||||
hints: vec![String::from("TCP connect to 1337.")],
|
||||
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::net::{TcpListener, TcpStream};
|
||||
|
||||
use super::{Challenge, ChallengeDesc};
|
||||
use super::{ChallengeDesc, ChallengeLike};
|
||||
use crate::config::Config;
|
||||
use crate::has_won;
|
||||
use crate::vault::VaultRef;
|
||||
|
@ -47,7 +47,7 @@ impl C2 {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Challenge for C2 {
|
||||
impl ChallengeLike for C2 {
|
||||
fn config(&self) -> Config {
|
||||
self.config.clone()
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ impl Challenge for C2 {
|
|||
}
|
||||
fn text() -> ChallengeDesc {
|
||||
ChallengeDesc {
|
||||
id: 2,
|
||||
title: "TCP dialogue".to_string(),
|
||||
hints: vec![String::from(
|
||||
"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::time::Instant;
|
||||
|
||||
use super::{Challenge, ChallengeDesc};
|
||||
use super::{ChallengeDesc, ChallengeLike};
|
||||
use crate::config::Config;
|
||||
use crate::has_won;
|
||||
use crate::vault::VaultRef;
|
||||
|
@ -207,7 +207,7 @@ impl C3 {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Challenge for C3 {
|
||||
impl ChallengeLike for C3 {
|
||||
fn config(&self) -> Config {
|
||||
self.config.clone()
|
||||
}
|
||||
|
@ -219,6 +219,7 @@ impl Challenge for C3 {
|
|||
}
|
||||
fn text() -> ChallengeDesc {
|
||||
ChallengeDesc {
|
||||
id: 3,
|
||||
title: "TCP math exam".to_string(),
|
||||
hints: vec![
|
||||
"TCP connect to 1337 and answer the questions.".to_string(),
|
||||
|
|
|
@ -16,6 +16,7 @@ pub mod c3;
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ChallengeDesc {
|
||||
id: usize,
|
||||
title: String,
|
||||
hints: Vec<String>,
|
||||
solution: String,
|
||||
|
@ -30,7 +31,7 @@ impl ChallengeDesc {
|
|||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of strings containing hints for the challenge.
|
||||
/// A [`Vec<String>`] containing hints for the challenge.
|
||||
pub fn hints(&self) -> Vec<&str> {
|
||||
self.hints.iter().map(|a| a.as_ref()).collect()
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ impl ChallengeDesc {
|
|||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A string containing the solution to the challenge.
|
||||
/// A [`String`] containing the solution to the challenge.
|
||||
pub fn solution(&self) -> &str {
|
||||
&self.solution
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ impl ChallengeDesc {
|
|||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A string containing the description to the challenge.
|
||||
/// A [`String`] containing the description to the challenge.
|
||||
pub fn description(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
@ -62,17 +63,27 @@ impl ChallengeDesc {
|
|||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A string containing the title to the challenge.
|
||||
/// A [`String`] containing the title to the challenge.
|
||||
pub fn title(&self) -> &str {
|
||||
&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.
|
||||
///
|
||||
/// Any type that implements this trait can be served as a challenge in the Wooly Vault application.
|
||||
#[async_trait]
|
||||
pub trait Challenge
|
||||
pub trait ChallengeLike
|
||||
where
|
||||
Self: Sized + 'static,
|
||||
Self: Send,
|
||||
|
@ -127,6 +138,7 @@ where
|
|||
async fn start(&self) -> anyhow::Result<()> {
|
||||
let c = self.clone();
|
||||
tokio::spawn(async move {
|
||||
info!("starting C{}", Self::text().id());
|
||||
if let Err(e) = c.serve().await {
|
||||
error!("challenge {} has crashed! {e:#?}", Self::text().title());
|
||||
};
|
||||
|
@ -134,34 +146,3 @@ where
|
|||
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
|
||||
//! 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;
|
||||
|
||||
pub mod challenge;
|
||||
|
@ -31,3 +37,61 @@ pub(crate) async fn has_won(
|
|||
vault.add_winner(contestant.clone()).await;
|
||||
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 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")]
|
||||
async fn main() -> Result<()> {
|
||||
|
@ -21,7 +22,7 @@ async fn main() -> Result<()> {
|
|||
let secret = Config::secret()?;
|
||||
let v = Vault::new(&secret);
|
||||
|
||||
select_and_start(conf.challenge, conf, v).await?;
|
||||
start_all(conf, v).await?;
|
||||
|
||||
loop {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await
|
||||
|
|
|
@ -26,27 +26,21 @@ pub struct Service<'tp> {
|
|||
challenges: Vec<ChallengeDesc>,
|
||||
}
|
||||
impl<'tp> Service<'tp> {
|
||||
fn new(
|
||||
vault: VaultRef,
|
||||
config: Config,
|
||||
env: Environment<'tp>,
|
||||
challenges: Vec<ChallengeDesc>,
|
||||
) -> Arc<Self> {
|
||||
Self {
|
||||
fn build(vault: VaultRef, config: Config, challenges: Vec<ChallengeDesc>) -> Result<Arc<Self>> {
|
||||
let mut env = Environment::new();
|
||||
env.add_template("index", include_str!("../../data/www/admin.html"))?;
|
||||
Ok(Self {
|
||||
vault,
|
||||
config,
|
||||
env,
|
||||
challenges,
|
||||
}
|
||||
.into()
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve(challenges: Vec<ChallengeDesc>, vault: VaultRef, config: Config) -> Result<()> {
|
||||
let mut env = Environment::new();
|
||||
env.add_template("index", include_str!("../../data/www/admin.html"))?;
|
||||
|
||||
let service = Service::new(vault, config, env, challenges);
|
||||
let service = Service::build(vault, config, challenges)?;
|
||||
|
||||
let routes = Service::admin_routes(service.clone())
|
||||
.or(Service::ressources_routes())
|
||||
|
|
Loading…
Reference in New Issue