feat: Logging

Also initial progress on the upload interface
This commit is contained in:
quexeky
2026-01-19 18:54:41 +11:00
parent 320d323880
commit 6e21e40648
13 changed files with 1198 additions and 72 deletions
+25 -10
View File
@@ -1,4 +1,6 @@
use clap::{Parser, Subcommand};
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand, ValueEnum};
#[derive(Parser)]
#[command(version, about, long_about = None)]
@@ -19,15 +21,28 @@ pub enum Commands {
url: String,
/// API token for non-interactive configuration.
#[arg(short, long)]
token: Option<String>
token: Option<String>,
},
/// Uploads new game version to depot
Upload {
/// Path of new version
path: bool,
/// ID of game to attach to
game_id: String,
/// Version ID to attach to
version_id: String,
},
Upload(UploadInfo),
}
#[derive(Args)]
pub struct UploadInfo {
/// Sets
pub upload_style: UploadStyle,
/// Path of new version
#[arg(short, long)]
pub path: PathBuf,
/// ID of game to attach to
#[arg(short, long)]
pub game_id: String,
/// Version ID to attach to
#[arg(short, long)]
pub version_id: String,
}
#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
pub enum UploadStyle {
S3,
Nginx,
}
-2
View File
@@ -67,8 +67,6 @@ pub async fn validate_configuration(url: String, token: String) -> Result<()> {
}
}
Ok(())
}
+2 -1
View File
@@ -1 +1,2 @@
pub mod configure;
pub mod configure;
pub mod upload;
+34
View File
@@ -0,0 +1,34 @@
use std::path::Path;
use crate::{
cli::UploadInfo,
commands::upload::{uploadable::Uploadable, void::VoidUploadable},
manifest::generate_manifest,
};
use log::info;
pub async fn upload(info: &UploadInfo) -> anyhow::Result<()> {
let game_id = &info.game_id;
let path = &info.path;
let version_id = &info.version_id;
let manifest = generate_manifest(&Path::new(path)).await?;
let mut uploader: Box<dyn Uploadable> = match info.upload_style {
crate::cli::UploadStyle::S3 => Box::new(VoidUploadable::new()),
crate::cli::UploadStyle::Nginx => Box::new(VoidUploadable::new()),
};
info!("Uploading chunks");
for (id, data) in &manifest.chunks {
info!("Uploading chunk id {id}");
uploader.upload_chunk(game_id, version_id, id, data)?;
}
info!("Finished uploading chunks");
info!("Uploading manifest");
uploader.upload_manifest(manifest, game_id, version_id)?;
info!("Uploading speedtest");
uploader.upload_speedtest(game_id, version_id)?;
Ok(())
}
+4
View File
@@ -0,0 +1,4 @@
pub mod interface;
pub mod s3;
pub mod uploadable;
pub mod void;
+28
View File
@@ -0,0 +1,28 @@
use droplet_rs::manifest::{ChunkData, Manifest};
use crate::commands::upload::uploadable::Uploadable;
pub type S3 = aws_sdk_s3::Client;
impl Uploadable for S3 {
fn upload_chunk(
&mut self,
id: &String,
version: &String,
chunk_id: &String,
chunk: &ChunkData,
) -> anyhow::Result<()> {
todo!()
}
fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()> {
todo!()
}
fn upload_manifest(
&mut self,
manifest: Manifest,
game_id: &String,
version_id: &String,
) -> anyhow::Result<()> {
todo!()
}
}
+20
View File
@@ -0,0 +1,20 @@
use droplet_rs::manifest::{ChunkData, Manifest};
pub trait Uploadable {
fn upload_chunk(
&mut self,
id: &String,
version: &String,
chunk_id: &String,
chunk: &ChunkData,
) -> anyhow::Result<()>;
fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()>;
fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>;
}
pub enum UploadableConfig {
S3 {
api_secret: String,
api_key_identifier: String,
region: String,
},
}
+38
View File
@@ -0,0 +1,38 @@
use droplet_rs::manifest::{ChunkData, Manifest};
use log::warn;
use crate::commands::upload::uploadable::Uploadable;
pub struct VoidUploadable;
impl Uploadable for VoidUploadable {
fn upload_chunk(
&mut self,
_id: &String,
_version: &String,
_chunk_id: &String,
_chunk: &ChunkData,
) -> anyhow::Result<()> {
warn!("Uploading chunk to VoidUploader");
Ok(())
}
fn upload_speedtest(&mut self, _game_id: &String, _version_id: &String) -> anyhow::Result<()> {
warn!("Uploading speedtest to VoidUploader");
Ok(())
}
fn upload_manifest(
&mut self,
_manifest: Manifest,
_game_id: &String,
_version_id: &String,
) -> anyhow::Result<()> {
warn!("Uploading manifest to VoidUploader");
Ok(())
}
}
impl VoidUploadable {
pub fn new() -> Self {
Self
}
}
+70 -20
View File
@@ -1,35 +1,85 @@
use std::{env, path::PathBuf, sync::LazyLock};
use anyhow::Result;
use crate::{
cli::{Cli, Commands},
commands::{configure::interactive_configure, upload},
};
use clap::Parser;
use droplet_rs::manifest::generate_manifest_rusty;
use indicatif::{ProgressBar, ProgressStyle};
use tokio::runtime::Handle;
use crate::{cli::{Cli, Commands}, commands::configure::interactive_configure};
use fern::colors::{Color, ColoredLevelConfig};
use log::LevelFilter;
use std::env;
use std::fs;
use std::io;
mod cli;
mod commands;
pub static CLI: LazyLock<Cli> = LazyLock::new(|| Cli::parse());
mod manifest;
#[tokio::main]
async fn main() -> Result<()> {
match &CLI.command {
async fn main() -> anyhow::Result<()> {
configure_logging()?;
let cli = Cli::parse();
match &cli.command {
Commands::Configure { url, token } => {
if let Some(token) = token {
todo!()
} else {
interactive_configure(url.to_string()).await?;
}
},
Commands::Upload {
path,
game_id,
version_id,
} => todo!(),
}
Commands::Upload(info) => {
upload::interface::upload(info).await?;
}
};
Ok(())
}
pub fn configure_logging() -> anyhow::Result<()> {
let log_level = env::var("RUST_LOG")
.or_else(|_| env::var("LOG_LEVEL"))
.unwrap_or_else(|_| "info".to_string())
.parse::<LevelFilter>()?;
let log_dir = env::var("LOG_FILE_DIR").unwrap_or_else(|_| "logs".to_string());
fs::create_dir_all(&log_dir)?;
let colors = ColoredLevelConfig::new()
.error(Color::Red)
.warn(Color::Yellow)
.info(Color::Green)
.debug(Color::Blue)
.trace(Color::Magenta);
fern::Dispatch::new()
.chain(
// Console output with colors and formatting
fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"[{}] {} {} - {}",
chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
colors.color(record.level()),
record.target(),
message
))
})
.chain(io::stdout()),
)
.chain(
// File output without colors and with formatting
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{}] {} {} - {}",
chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
record.level(),
record.target(),
message
))
})
.chain(fern::log_file(format!("{}/app.log", log_dir))?),
)
.level(log_level)
.apply()?;
Ok(())
}
+26
View File
@@ -0,0 +1,26 @@
use std::{
fs,
io::{Read, Seek},
path::Path,
};
use droplet_rs::manifest::{Manifest, generate_manifest_rusty};
use indicatif::{ProgressBar, ProgressStyle};
pub async fn generate_manifest(dir: &Path) -> anyhow::Result<Manifest> {
let progress_bar = ProgressBar::new(100_00).with_style(
ProgressStyle::default_bar()
.template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%")
.unwrap(),
);
let res = generate_manifest_rusty(
dir,
|progress| {
let progress_int = (progress * 100f32).round() as u64;
progress_bar.set_position(progress_int);
},
|log| progress_bar.println(log),
)
.await;
res
}