From 738f9c947b4fc771abf2c253bdc24be3514a4985 Mon Sep 17 00:00:00 2001 From: Guilherme Werner Date: Wed, 4 Jun 2025 11:30:22 -0300 Subject: [PATCH] Add utils crates --- Cargo.toml | 6 ++ examples/agent.rs | 10 ++++ src/constants/Cargo.toml | 20 +++++++ src/constants/build.rs | 8 +++ src/constants/lib.rs | 19 +++++++ src/error/Cargo.toml | 17 ++++++ src/error/lib.rs | 7 +++ src/json/Cargo.toml | 18 ++++++ src/json/lib.rs | 49 ++++++++++++++++ src/json/test.json | 3 + src/lib.rs | 3 +- src/log/Cargo.toml | 20 +++++++ src/log/colors.rs | 19 +++++++ src/log/lib.rs | 118 +++++++++++++++++++++++++++++++++++++++ src/log/log_config.rs | 22 ++++++++ src/platform/Cargo.toml | 20 +++++++ src/platform/lib.rs | 4 ++ src/platform/paths.rs | 50 +++++++++++++++++ 18 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 examples/agent.rs create mode 100644 src/constants/Cargo.toml create mode 100644 src/constants/build.rs create mode 100644 src/constants/lib.rs create mode 100644 src/error/Cargo.toml create mode 100644 src/error/lib.rs create mode 100644 src/json/Cargo.toml create mode 100644 src/json/lib.rs create mode 100644 src/json/test.json create mode 100644 src/log/Cargo.toml create mode 100644 src/log/colors.rs create mode 100644 src/log/lib.rs create mode 100644 src/log/log_config.rs create mode 100644 src/platform/Cargo.toml create mode 100644 src/platform/lib.rs create mode 100644 src/platform/paths.rs diff --git a/Cargo.toml b/Cargo.toml index e71c290..c5361da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,12 +22,18 @@ exclude = [ "scripts/", ] +[workspace] +resolver = "2" +members = ["src/*"] +exclude = ["src/apis", "src/models"] + [lib] name = "tribufu" crate-type = ["rlib"] path = "src/lib.rs" [dependencies] +tribufu-constants = { version = "0.0.5", path = "./src/constants" } async-trait = "^0.1" reqwest = { version = "^0.12", features = ["json", "multipart"] } serde = { version = "^1.0", features = ["derive"] } diff --git a/examples/agent.rs b/examples/agent.rs new file mode 100644 index 0000000..20379ab --- /dev/null +++ b/examples/agent.rs @@ -0,0 +1,10 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use tribufu::TribufuApi; + +#[tokio::main] +async fn main() { + let user_agent = TribufuApi::get_user_agent(); + println!("{}", user_agent); +} diff --git a/src/constants/Cargo.toml b/src/constants/Cargo.toml new file mode 100644 index 0000000..2cc5dfa --- /dev/null +++ b/src/constants/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tribufu-constants" +version = "0.0.5" +description = "Tribufu Constants" +repository = "https://github.com/tribufu/tribufu-rust" +authors = ["Tribufu "] +edition = "2021" +publish = false + +[lib] +name = "tribufu_constants" +crate-type = ["rlib"] +path = "lib.rs" + +[build-dependencies] +vergen = { version = "=5.1.5", default-features = false, features = [ + "build", + "cargo", + "rustc", +] } diff --git a/src/constants/build.rs b/src/constants/build.rs new file mode 100644 index 0000000..b36f03c --- /dev/null +++ b/src/constants/build.rs @@ -0,0 +1,8 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use vergen::{vergen, Config}; + +fn main() { + vergen(Config::default()).unwrap(); +} diff --git a/src/constants/lib.rs b/src/constants/lib.rs new file mode 100644 index 0000000..69c67ac --- /dev/null +++ b/src/constants/lib.rs @@ -0,0 +1,19 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use std::env::consts; + +pub const BUILD_TIMESTAMP: &'static str = env!("VERGEN_BUILD_TIMESTAMP"); +pub const CARGO_PROFILE: &'static str = env!("VERGEN_CARGO_PROFILE"); +pub const LLVM_VERSION: &'static str = env!("VERGEN_RUSTC_LLVM_VERSION"); +pub const RUSTC_CHANNEL: &'static str = env!("VERGEN_RUSTC_CHANNEL"); +pub const RUSTC_COMMIT: &'static str = env!("VERGEN_RUSTC_COMMIT_HASH"); +pub const RUSTC_VERSION: &'static str = env!("VERGEN_RUSTC_SEMVER"); +pub const TARGET_ARCH: &'static str = consts::ARCH; +pub const TARGET_DLL_EXTENSION: &'static str = consts::DLL_EXTENSION; +pub const TARGET_DLL_SUFFIX: &'static str = consts::DLL_SUFFIX; +pub const TARGET_EXE_EXTENSION: &'static str = consts::EXE_EXTENSION; +pub const TARGET_EXE_SUFFIX: &'static str = consts::EXE_SUFFIX; +pub const TARGET_FAMILY: &'static str = consts::FAMILY; +pub const TARGET_OS: &'static str = consts::OS; +pub const TARGET_TRIPLE: &'static str = env!("VERGEN_CARGO_TARGET_TRIPLE"); diff --git a/src/error/Cargo.toml b/src/error/Cargo.toml new file mode 100644 index 0000000..5723bd9 --- /dev/null +++ b/src/error/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tribufu-error" +version = "0.0.5" +description = "Tribufu Error" +repository = "https://github.com/tribufu/tribufu-rust" +authors = ["Tribufu "] +edition = "2021" +publish = false + +[lib] +name = "tribufu_error" +crate-type = ["rlib"] +path = "lib.rs" + +[dependencies] +anyhow = "1.0.44" +thiserror = "2.0.12" diff --git a/src/error/lib.rs b/src/error/lib.rs new file mode 100644 index 0000000..da8f620 --- /dev/null +++ b/src/error/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +pub use anyhow::Error; +pub use thiserror::Error; + +pub type Result = core::result::Result; diff --git a/src/json/Cargo.toml b/src/json/Cargo.toml new file mode 100644 index 0000000..dda77d4 --- /dev/null +++ b/src/json/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tribufu-json" +version = "0.0.5" +description = "Tribufu Json" +repository = "https://github.com/tribufu/tribufu-rust" +authors = ["Tribufu "] +edition = "2021" +publish = false + +[lib] +name = "tribufu_json" +crate-type = ["rlib"] +path = "lib.rs" + +[dependencies] +tribufu-error = { version = "0.0.5", path = "../error" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/src/json/lib.rs b/src/json/lib.rs new file mode 100644 index 0000000..2236d8f --- /dev/null +++ b/src/json/lib.rs @@ -0,0 +1,49 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use serde::Serialize; +use serde_json::ser::PrettyFormatter; +use serde_json::Serializer; +use tribufu_error::Result; + +#[macro_export] +macro_rules! include_json { + ($path:expr) => { + $crate::from_str(include_str!($path)).expect("Failed to load JSON") + }; +} + +pub use serde_json::from_slice; +pub use serde_json::from_str; +pub use serde_json::to_string; +pub use serde_json::to_value; +pub use serde_json::to_vec_pretty; + +pub fn to_string_pretty(value: &T) -> Result +where + T: Serialize, +{ + let obj = to_value(value).expect("Failed to serialize JSON"); + let mut buf = Vec::new(); + let fmt = PrettyFormatter::with_indent(b" "); + let mut ser = Serializer::with_formatter(&mut buf, fmt); + obj.serialize(&mut ser)?; + Ok(String::from_utf8(buf)?) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Serialize, Deserialize)] + struct JsonTest { + version: String, + } + + #[test] + fn test_include_json() { + let data: JsonTest = include_json!("test.json"); + assert!(data.version == "0.0.0".to_owned()) + } +} diff --git a/src/json/test.json b/src/json/test.json new file mode 100644 index 0000000..7198571 --- /dev/null +++ b/src/json/test.json @@ -0,0 +1,3 @@ +{ + "version": "0.0.0" +} diff --git a/src/lib.rs b/src/lib.rs index b0d81a9..40caa51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ use crate::apis::configuration::{ApiKey, Configuration}; use crate::apis::tribufu_generated_api::TribufuGeneratedApiClient; use reqwest::Client; +use tribufu_constants::{RUSTC_VERSION, TARGET_TRIPLE}; use std::env::{self, consts}; use std::sync::Arc; @@ -68,7 +69,7 @@ impl TribufuApi { /// Gets the user agent string for the Tribufu API client. pub fn get_user_agent() -> String { let version = Self::get_version(); - format!("Tribufu/{} ({}; {})", version, consts::OS, consts::ARCH) + format!("Tribufu/{} (Rust {}; {})", version, RUSTC_VERSION, TARGET_TRIPLE) } /// Checks if debug mode is enabled. diff --git a/src/log/Cargo.toml b/src/log/Cargo.toml new file mode 100644 index 0000000..165babf --- /dev/null +++ b/src/log/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tribufu-log" +version = "0.0.5" +description = "Tribufu Log" +repository = "https://github.com/tribufu/tribufu-rust" +authors = ["Tribufu "] +edition = "2021" +publish = false + +[lib] +name = "tribufu_log" +crate-type = ["rlib"] +path = "lib.rs" + +[dependencies] +tribufu-error = { version = "0.0.5", path = "../error" } +chrono = "0.4.23" +env_logger = "0.10.1" +log = "0.4" +serde = { version = "1.0", features = ["derive"] } diff --git a/src/log/colors.rs b/src/log/colors.rs new file mode 100644 index 0000000..200d0aa --- /dev/null +++ b/src/log/colors.rs @@ -0,0 +1,19 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +pub const BLACK: u8 = 0; +pub const RED: u8 = 1; +pub const GREEN: u8 = 2; +pub const YELLOW: u8 = 3; +pub const BLUE: u8 = 4; +pub const MAGENTA: u8 = 5; +pub const CYAN: u8 = 6; +pub const WHITE: u8 = 7; +pub const BRIGHT_BLACK: u8 = 8; +pub const BRIGHT_RED: u8 = 9; +pub const BRIGHT_GREEN: u8 = 10; +pub const BRIGHT_YELLOW: u8 = 11; +pub const BRIGHT_BLUE: u8 = 12; +pub const BRIGHT_MAGENTA: u8 = 13; +pub const BRIGHT_CYAN: u8 = 14; +pub const BRIGHT_WHITE: u8 = 15; diff --git a/src/log/lib.rs b/src/log/lib.rs new file mode 100644 index 0000000..172d8c5 --- /dev/null +++ b/src/log/lib.rs @@ -0,0 +1,118 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use chrono::prelude::*; +pub use env_logger::fmt::Color; +use env_logger::{Builder, Target}; +pub use log::debug; +pub use log::error; +pub use log::info; +pub use log::trace; +pub use log::warn; +use log::Level; +use log::LevelFilter; +use serde::{Deserialize, Serialize}; +use std::io::Write; + +pub mod colors; + +mod log_config; +pub use log_config::*; + +pub fn init() { + let logger = Logger::from_env(None); + logger.init(); +} + +pub fn init_level(level: LogLevel) { + let logger = Logger::new(level.into()); + logger.init(); +} + +#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum LogLevel { + #[default] + Off, + Error, + Warn, + Info, + Debug, + Trace, +} + +impl LogLevel { + pub fn from_str(s: &str) -> Option { + match s { + "off" => Some(Self::Off), + "error" => Some(Self::Error), + "warn" => Some(Self::Warn), + "info" => Some(Self::Info), + "debug" => Some(Self::Debug), + "trace" => Some(Self::Trace), + _ => None, + } + } +} + +impl From for LevelFilter { + fn from(level: LogLevel) -> Self { + match level { + LogLevel::Off => LevelFilter::Off, + LogLevel::Error => LevelFilter::Error, + LogLevel::Warn => LevelFilter::Warn, + LogLevel::Info => LevelFilter::Info, + LogLevel::Debug => LevelFilter::Debug, + LogLevel::Trace => LevelFilter::Trace, + } + } +} + +pub struct Logger { + builder: Builder, +} + +impl Logger { + pub fn new(level: LevelFilter) -> Self { + let mut builder = Builder::new(); + builder.filter_level(level); + Self { builder } + } + + pub fn with_config(config: LogConfig) -> Self { + let mut builder = Builder::new(); + builder.filter_level(config.level.into()); + Self { builder } + } + + pub fn from_env(var: Option) -> Self { + let builder = Builder::from_env(var.unwrap_or("LOG_LEVEL".to_string())); + Self { builder } + } + + pub fn init(mut self) { + self.builder + .target(Target::Stdout) + .format(|fmt, record| { + let mut style = fmt.style(); + + match record.level() { + Level::Error => style.set_color(Color::Ansi256(colors::RED)), + Level::Warn => style.set_color(Color::Ansi256(colors::YELLOW)), + Level::Info => style.set_color(Color::Ansi256(colors::GREEN)), + Level::Debug => style.set_color(Color::Ansi256(colors::WHITE)), + Level::Trace => style.set_color(Color::Ansi256(colors::BRIGHT_BLACK)), + }; + + let line = format!( + "[{}] [{}]: {}", + Local::now().format("%Y-%m-%dT%H:%M:%S"), + record.level(), + record.args() + ); + + writeln!(fmt, "{}", style.value(line)) + }) + .init(); + } +} diff --git a/src/log/log_config.rs b/src/log/log_config.rs new file mode 100644 index 0000000..fad7b15 --- /dev/null +++ b/src/log/log_config.rs @@ -0,0 +1,22 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use crate::LogLevel; +use serde::{Deserialize, Serialize}; +use std::env; +use tribufu_error::Result; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct LogConfig { + pub level: LogLevel, + pub file: Option, +} + +impl LogConfig { + pub fn from_env() -> Result { + Ok(Self { + level: LogLevel::from_str(&env::var("LOG_LEVEL")?).unwrap_or_default(), + file: env::var("LOG_FILE").ok(), + }) + } +} diff --git a/src/platform/Cargo.toml b/src/platform/Cargo.toml new file mode 100644 index 0000000..88935d7 --- /dev/null +++ b/src/platform/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tribufu-platform" +version = "0.0.5" +description = "Tribufu Platform" +repository = "https://github.com/tribufu/tribufu-rust" +authors = ["Tribufu "] +edition = "2021" +publish = false + +[lib] +name = "tribufu_platform" +crate-type = ["rlib"] +path = "lib.rs" + +[dependencies] +tribufu-error = { version = "0.0.5", path = "../error" } +dunce = "1.0.4" + +[target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies] +dirs = "5.0.1" diff --git a/src/platform/lib.rs b/src/platform/lib.rs new file mode 100644 index 0000000..573d4ff --- /dev/null +++ b/src/platform/lib.rs @@ -0,0 +1,4 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +pub mod paths; diff --git a/src/platform/paths.rs b/src/platform/paths.rs new file mode 100644 index 0000000..1f9507c --- /dev/null +++ b/src/platform/paths.rs @@ -0,0 +1,50 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +use std::env; +use std::path::PathBuf; +use tribufu_error::Result; + +/// Gets the root base directory of the application. +pub fn app_dir() -> Result { + let mut path = dunce::canonicalize(env::current_exe()?)?; // /bin/platform/app.exe + path.pop(); // /bin + path.pop(); // / + Ok(path) +} + +/// Gets the path to the platform-specific binary directory. +pub fn bin_dir() -> Result { + let base_dir = app_dir()?; + + #[cfg(all(target_os = "macos", not(debug_assertions)))] + return Ok(base_dir.join("MacOS")); + + #[cfg(not(all(target_os = "macos", not(debug_assertions))))] + Ok(base_dir.join("bin")) +} + +/// Gets the path to the configuration directory. +pub fn config_dir() -> Result { + Ok(app_dir()?.join("config")) +} + +/// Gets the path to the assets directory. +pub fn assets_dir() -> Result { + Ok(app_dir()?.join("assets")) +} + +/// Gets the path to the saved data directory. +pub fn saved_dir() -> Result { + Ok(app_dir()?.join("saved")) +} + +/// Gets the path to the cache directory inside `saved`. +pub fn cache_dir() -> Result { + Ok(saved_dir()?.join("cache")) +} + +/// Gets the path to the logs directory inside `saved`. +pub fn logs_dir() -> Result { + Ok(saved_dir()?.join("logs")) +}