mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-06-22 04:11:32 +10:00
feat: Logging
Also initial progress on the upload interface
This commit is contained in:
@@ -1 +1,2 @@
|
||||
/target
|
||||
logs/
|
||||
Generated
+945
-38
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -5,11 +5,15 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.100"
|
||||
aws-sdk-s3 = "1.120.0"
|
||||
chrono = "0.4.43"
|
||||
clap = { version = "4.5.54", features = ["derive"] }
|
||||
console = "0.16.2"
|
||||
dialoguer = "0.12.0"
|
||||
droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.11.1" }
|
||||
droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.14" }
|
||||
fern = { version = "0.7.1", features = ["colored"] }
|
||||
indicatif = "0.18.3"
|
||||
log = "0.4.29"
|
||||
reqwest = { version = "0.13.1", features = ["json"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.148"
|
||||
|
||||
+25
-10
@@ -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,
|
||||
}
|
||||
|
||||
@@ -67,8 +67,6 @@ pub async fn validate_configuration(url: String, token: String) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod configure;
|
||||
pub mod configure;
|
||||
pub mod upload;
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod interface;
|
||||
pub mod s3;
|
||||
pub mod uploadable;
|
||||
pub mod void;
|
||||
@@ -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!()
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
@@ -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
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user