Browse Source

WIP: refactor

develop-refactor
chodak166 4 months ago
parent
commit
307971e600
  1. 1
      app/Cargo.toml
  2. 46
      app/src/app.rs
  3. 57
      app/src/config.rs
  4. 2
      app/src/main.rs
  5. 4
      lib/src/core/traits.rs
  6. 8
      lib/src/presentation/cli.rs
  7. 98
      lib/src/presentation/cli/cli_args.rs
  8. 41
      lib/src/presentation/cli/defaults.rs

1
app/Cargo.toml

@ -13,6 +13,7 @@ tokio = { version = "1.48", features = ["full"] }
anyhow = "1.0" anyhow = "1.0"
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
async-trait = "0.1"
# Configuration & Inputs # Configuration & Inputs
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

46
app/src/app.rs

@ -1,10 +1,10 @@
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::container::Container; use crate::container::Container;
use crate::handlers::resolve_command;
use anyhow::Result; use anyhow::Result;
use applib::cli::{CliArgs, Command, commands}; use applib::cli::{CliArgs, Command};
use clap::Parser; use clap::Parser;
use tokio::signal; use tracing::debug;
use tracing::{debug, info, warn};
pub struct Application { pub struct Application {
config: AppConfig, config: AppConfig,
@ -16,7 +16,10 @@ impl Application {
pub async fn build() -> Result<Self> { pub async fn build() -> Result<Self> {
let args = CliArgs::parse(); let args = CliArgs::parse();
let config = AppConfig::build(&args.global, &args.command)?; // Resolve the command once to get the trait object for configuration
let handler = resolve_command(&args.command);
let config = AppConfig::build(&args.global, handler)?;
tracing_subscriber::fmt() tracing_subscriber::fmt()
.compact() .compact()
@ -36,38 +39,7 @@ impl Application {
} }
pub async fn run(self) -> Result<()> { pub async fn run(self) -> Result<()> {
match self.command { let handler = resolve_command(&self.command);
Command::Server(_) => { handler.execute(&self.config, &self.container).await
let config = self.config.server.expect("Server config not set");
commands::server::run(config, Self::wait_for_shutdown_signal()).await;
}
Command::Decode(_) => {
let config = self.config.decoder.expect("Decoder config not set");
commands::decode::run(config).await;
}
Command::Encode(_) => {
let config = self.config.encoder.expect("Encoder config not set");
let repo = self.container.create_dict_repo("demo_pl").await?;
commands::encode::run(config, repo.as_ref()).await;
}
Command::ImportDict(_) => {
let config = self.config.import_dict.expect("ImportDict config not set");
let importer = self.container.create_dict_importer(&config.name).await?;
commands::import_dict::run(config, importer).await?;
}
}
Ok(())
}
async fn wait_for_shutdown_signal() {
match signal::ctrl_c().await {
Ok(()) => {
info!("Received shutdown signal (SIGINT/SIGTERM)");
}
Err(err) => {
warn!("Failed to listen for shutdown signal: {}", err);
}
}
} }
} }

57
app/src/config.rs

@ -2,7 +2,7 @@ use anyhow::{Context, Result};
use config::{Config, Environment, File}; use config::{Config, Environment, File};
use serde::Deserialize; use serde::Deserialize;
use applib::cli::{Command, GlobalArgs, defaults::set_command_defaults}; use applib::cli::{ConfigurableCommand, GlobalArgs};
use applib::config::*; use applib::config::*;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
@ -19,11 +19,11 @@ pub struct AppConfig {
} }
impl AppConfig { impl AppConfig {
pub fn build(args: &GlobalArgs, command: &Command) -> Result<Self> { pub fn build(args: &GlobalArgs, handler: &dyn ConfigurableCommand) -> Result<Self> {
let mut builder = Config::builder(); let mut builder = Config::builder();
// Command-specific defaults // Command-specific defaults via Trait
builder = set_command_defaults(builder, command)?; builder = handler.apply_defaults(builder)?;
// File Layer // File Layer
let config_path = &args.config; let config_path = &args.config;
@ -34,8 +34,13 @@ impl AppConfig {
// Environment Layer (APP_SERVER_PORT) // Environment Layer (APP_SERVER_PORT)
builder = builder.add_source(Environment::with_prefix("APP").separator("_")); builder = builder.add_source(Environment::with_prefix("APP").separator("_"));
// CLI Overrides Layer // Global log level override
builder = apply_cli_overrides(builder, args, command)?; if let Some(ref level) = args.log_level {
builder = builder.set_override("log_level", level.clone())?;
}
// Command-specific overrides via Trait
builder = handler.apply_overrides(builder)?;
builder builder
.build() .build()
@ -44,43 +49,3 @@ impl AppConfig {
.context("Failed to deserialize Config") .context("Failed to deserialize Config")
} }
} }
fn apply_cli_overrides(
builder: config::ConfigBuilder<config::builder::DefaultState>,
args: &GlobalArgs,
command: &Command,
) -> Result<config::ConfigBuilder<config::builder::DefaultState>> {
let mut builder = builder;
// Global log level override
if let Some(ref level) = args.log_level {
builder = builder.set_override("log_level", level.clone())?;
}
// Command-specific overrides
match command {
Command::Server(cmd_args) => {
if let Some(port) = cmd_args.port {
builder = builder.set_override("server.port", port)?;
}
}
Command::Decode(cmd_args) => {
if let Some(name) = &cmd_args.system {
builder = builder.set_override("decoder.system", name.as_str())?;
}
builder = builder.set_override("decoder.input", cmd_args.input.clone())?;
}
Command::Encode(cmd_args) => {
if let Some(name) = &cmd_args.system {
builder = builder.set_override("encoder.system", name.as_str())?;
}
builder = builder.set_override("encoder.input", cmd_args.input.clone())?;
}
Command::ImportDict(cmd_args) => {
builder = builder.set_override("import_dict.name", cmd_args.name.clone())?;
builder = builder.set_override("import_dict.path", cmd_args.path.clone())?;
}
}
Ok(builder)
}

2
app/src/main.rs

@ -1,6 +1,8 @@
mod app; mod app;
mod config; mod config;
mod container; mod container;
mod handlers;
mod traits;
use anyhow::Result; use anyhow::Result;
use app::Application; use app::Application;

4
lib/src/core/traits.rs

@ -6,11 +6,11 @@ use crate::core::errors::CodecError;
use super::entities::{DecodedValue, Dict, DictEntry}; use super::entities::{DecodedValue, Dict, DictEntry};
use super::errors::RepositoryError; use super::errors::RepositoryError;
pub trait SystemDecoder { pub trait SystemDecoder: Send + Sync {
fn decode(&self, word: &str) -> Result<DecodedValue, CodecError>; fn decode(&self, word: &str) -> Result<DecodedValue, CodecError>;
} }
pub trait SystemEncoder { pub trait SystemEncoder: Send + Sync {
fn initialize(&self) -> Result<(), CodecError>; fn initialize(&self) -> Result<(), CodecError>;
fn encode(&self, word: &str) -> Result<EncodedValue, CodecError>; fn encode(&self, word: &str) -> Result<EncodedValue, CodecError>;
} }

8
lib/src/presentation/cli.rs

@ -1,7 +1,9 @@
pub mod cli_args; pub mod cli_args;
pub mod commands; pub mod commands;
pub mod defaults; pub mod defaults;
pub mod traits;
pub use self::cli_args::CliArgs; pub use self::cli_args::{
pub use self::cli_args::Command; CliArgs, Command, DecodeArgs, EncodeArgs, GlobalArgs, ImportDictArgs, ServerArgs,
pub use self::cli_args::GlobalArgs; };
pub use self::traits::ConfigurableCommand;

98
lib/src/presentation/cli/cli_args.rs

@ -1,5 +1,8 @@
use crate::cli::defaults; use crate::cli::{ConfigurableCommand, defaults};
use anyhow::Result;
use clap::{Args as ClapArgs, Parser, Subcommand}; use clap::{Args as ClapArgs, Parser, Subcommand};
use config::ConfigBuilder;
use config::builder::DefaultState;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -43,6 +46,29 @@ pub struct ServerArgs {
pub port: Option<u16>, pub port: Option<u16>,
} }
impl ConfigurableCommand for ServerArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("server.host", defaults::HOST)?
.set_default("server.port", defaults::PORT)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(port) = self.port {
builder = builder.set_override("server.port", port)?;
}
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)] #[derive(ClapArgs, Debug, Clone)]
pub struct DecodeArgs { pub struct DecodeArgs {
#[arg(long, help = defaults::HELP_DEC_SYSTEM)] #[arg(long, help = defaults::HELP_DEC_SYSTEM)]
@ -52,6 +78,30 @@ pub struct DecodeArgs {
pub input: String, pub input: String,
} }
impl ConfigurableCommand for DecodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("decoder.system", defaults::SYSTEM_NAME)?
.set_default("decoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("decoder.system", system.clone())?;
}
builder = builder.set_override("decoder.input", self.input.clone())?;
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)] #[derive(ClapArgs, Debug, Clone)]
pub struct EncodeArgs { pub struct EncodeArgs {
#[arg(long, help = defaults::HELP_ENC_SYSTEM)] #[arg(long, help = defaults::HELP_ENC_SYSTEM)]
@ -61,6 +111,30 @@ pub struct EncodeArgs {
pub input: String, pub input: String,
} }
impl ConfigurableCommand for EncodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("encoder.system", defaults::SYSTEM_NAME)?
.set_default("encoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("encoder.system", system.clone())?;
}
builder = builder.set_override("encoder.input", self.input.clone())?;
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)] #[derive(ClapArgs, Debug, Clone)]
pub struct ImportDictArgs { pub struct ImportDictArgs {
#[arg(long, help = defaults::HELP_IMPORT_DICT_NAME)] #[arg(long, help = defaults::HELP_IMPORT_DICT_NAME)]
@ -69,3 +143,25 @@ pub struct ImportDictArgs {
#[arg(long, help = defaults::HELP_IMPORT_DICT_INPUT)] #[arg(long, help = defaults::HELP_IMPORT_DICT_INPUT)]
pub path: String, pub path: String,
} }
impl ConfigurableCommand for ImportDictArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("import_dict.name", defaults::IMPORT_DICT_NAME)?
.set_default("import_dict.path", defaults::IMPORT_DICT_PATH)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_override("import_dict.name", self.name.clone())?
.set_override("import_dict.path", self.path.clone())
.map_err(Into::into)
}
}

41
lib/src/presentation/cli/defaults.rs

@ -1,10 +1,3 @@
use anyhow::Result;
pub use config::ConfigBuilder;
use const_format::formatcp;
use crate::cli::Command;
pub const HOST: &str = "127.0.0.1"; pub const HOST: &str = "127.0.0.1";
pub const PORT: u16 = 8080; pub const PORT: u16 = 8080;
pub const LOG_LEVEL: &str = "info"; pub const LOG_LEVEL: &str = "info";
@ -12,6 +5,8 @@ pub const SYSTEM_NAME: &str = "major_pl";
pub const IMPORT_DICT_NAME: &str = ""; pub const IMPORT_DICT_NAME: &str = "";
pub const IMPORT_DICT_PATH: &str = ""; pub const IMPORT_DICT_PATH: &str = "";
use const_format::formatcp;
pub const HELP_PORT: &str = formatcp!("Override Port [default: {}]", PORT); pub const HELP_PORT: &str = formatcp!("Override Port [default: {}]", PORT);
pub const HELP_LOG: &str = formatcp!("Override Log Level [default: {}]", LOG_LEVEL); pub const HELP_LOG: &str = formatcp!("Override Log Level [default: {}]", LOG_LEVEL);
pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", SYSTEM_NAME); pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", SYSTEM_NAME);
@ -20,35 +15,3 @@ pub const HELP_ENC_SYSTEM: &str = formatcp!("System to use [default: {}]", SYSTE
pub const HELP_ENC_INPUT: &str = formatcp!("Number to encode"); pub const HELP_ENC_INPUT: &str = formatcp!("Number to encode");
pub const HELP_IMPORT_DICT_NAME: &str = formatcp!("Dictionary name"); pub const HELP_IMPORT_DICT_NAME: &str = formatcp!("Dictionary name");
pub const HELP_IMPORT_DICT_INPUT: &str = formatcp!("Dictionary file path"); pub const HELP_IMPORT_DICT_INPUT: &str = formatcp!("Dictionary file path");
pub fn set_command_defaults(
builder: ConfigBuilder<config::builder::DefaultState>,
command: &Command,
) -> Result<ConfigBuilder<config::builder::DefaultState>> {
let mut builder = builder.set_default("log_level", LOG_LEVEL)?;
match command {
Command::Server(_) => {
builder = builder
.set_default("server.host", HOST)?
.set_default("server.port", PORT)?;
}
Command::Decode(_) => {
builder = builder
.set_default("decoder.system", SYSTEM_NAME)?
.set_default("decoder.input", "")?;
}
Command::Encode(_) => {
builder = builder
.set_default("encoder.system", SYSTEM_NAME)?
.set_default("encoder.input", "")?;
}
Command::ImportDict(_) => {
builder = builder
.set_default("import_dict.name", IMPORT_DICT_NAME)?
.set_default("import_dict.path", IMPORT_DICT_PATH)?;
}
}
Ok(builder)
}

Loading…
Cancel
Save