Browse Source

WIP: refactor

develop-refactor
chodak166 4 months ago
parent
commit
da43970a46
  1. 13
      app/src/commands.rs
  2. 54
      app/src/commands/decode.rs
  3. 68
      app/src/commands/encode.rs
  4. 9
      app/src/commands/import_dict.rs
  5. 81
      app/src/commands/server.rs
  6. 29
      app/src/config.rs
  7. 39
      app/src/container.rs
  8. 13
      app/src/defaults.rs
  9. 1
      app/src/main.rs
  10. 2
      lib/src/common/entities.rs

13
app/src/commands.rs

@ -1,11 +1,9 @@
pub mod decode; pub mod decode;
pub mod encode; pub mod encode;
pub mod import_dict; pub mod import_dict;
pub mod server;
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::container::Container; use crate::container::Container;
use crate::defaults;
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use clap::Subcommand; use clap::Subcommand;
@ -16,9 +14,6 @@ use std::path::PathBuf;
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum Command { pub enum Command {
/// Start the application server
Server(server::ServerArgs),
/// Decode a word using given system /// Decode a word using given system
Decode(decode::DecodeArgs), Decode(decode::DecodeArgs),
@ -31,7 +26,6 @@ pub enum Command {
pub fn resolve_command(command: &Command) -> &dyn AppCommand { pub fn resolve_command(command: &Command) -> &dyn AppCommand {
match command { match command {
Command::Server(args) => args,
Command::Decode(args) => args, Command::Decode(args) => args,
Command::Encode(args) => args, Command::Encode(args) => args,
Command::ImportDict(args) => args, Command::ImportDict(args) => args,
@ -79,3 +73,10 @@ pub trait CommandExecutor {
pub trait AppCommand: ConfigurableCommand + CommandExecutor {} pub trait AppCommand: ConfigurableCommand + CommandExecutor {}
impl<T: ConfigurableCommand + CommandExecutor> AppCommand for T {} impl<T: ConfigurableCommand + CommandExecutor> AppCommand for T {}
mod defaults {
use const_format::formatcp;
pub const LOG_LEVEL: &str = "info";
pub const HELP_LOG: &str = formatcp!("Override Log Level [default: {}]", LOG_LEVEL);
}

54
app/src/commands/decode.rs

@ -3,22 +3,12 @@ use crate::config::AppConfig;
use crate::config::System; use crate::config::System;
use crate::container::Container; use crate::container::Container;
use anyhow::Result; use anyhow::{Context, Result};
use applib::SystemDecoder;
use applib::sys_major::decoder::Decoder;
use applib::sys_major::{self as major};
use async_trait::async_trait; use async_trait::async_trait;
use config::ConfigBuilder; use config::ConfigBuilder;
use config::builder::DefaultState; use config::builder::DefaultState;
use serde::Deserialize; use serde::Deserialize;
mod defaults {
use const_format::formatcp;
pub const DEC_SYSTEM_NAME: &str = "major_pl";
pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", DEC_SYSTEM_NAME);
pub const HELP_DEC_INPUT: &str = formatcp!("Text to decode");
}
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct Config { pub struct Config {
pub system: System, pub system: System,
@ -27,10 +17,10 @@ pub struct Config {
#[derive(ClapArgs, Debug, Clone)] #[derive(ClapArgs, Debug, Clone)]
pub struct DecodeArgs { pub struct DecodeArgs {
#[arg(long, help = defaults::HELP_DEC_SYSTEM)] #[arg(short, long, help = defaults::HELP_DEC_SYSTEM)]
pub system: Option<String>, pub system: Option<String>,
#[arg(long, help = defaults::HELP_DEC_INPUT)] #[arg(short, long, help = defaults::HELP_DEC_INPUT)]
pub input: String, pub input: String,
} }
@ -40,8 +30,8 @@ impl ConfigurableCommand for DecodeArgs {
builder: ConfigBuilder<DefaultState>, builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> { ) -> Result<ConfigBuilder<DefaultState>> {
builder builder
.set_default("decoder.system", defaults::DEC_SYSTEM_NAME)? .set_default("decode.system", defaults::DEC_SYSTEM_NAME)?
.set_default("decoder.input", "") .set_default("decode.input", "")
.map_err(Into::into) .map_err(Into::into)
} }
@ -51,27 +41,37 @@ impl ConfigurableCommand for DecodeArgs {
) -> Result<ConfigBuilder<DefaultState>> { ) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder; let mut builder = builder;
if let Some(ref system) = self.system { if let Some(ref system) = self.system {
builder = builder.set_override("decoder.system", system.clone())?; builder = builder.set_override("decode.system", system.clone())?;
} }
builder = builder.set_override("decoder.input", self.input.clone())?; builder = builder.set_override("decode.input", self.input.clone())?;
Ok(builder) Ok(builder)
} }
} }
#[async_trait] #[async_trait]
impl CommandExecutor for DecodeArgs { impl CommandExecutor for DecodeArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> { async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config.decoder.as_ref().expect("Decoder config not set"); let config = config
.decode
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Decoder config missing"))?;
let decoder: Box<dyn SystemDecoder> = match config.system { let decoder = container.create_decoder(&config)?;
System::MajorPl => Box::new(Decoder::new(major::rules_pl::get_rules())),
System::MajorEn => Box::new(Decoder::new(major::rules_en::get_rules())),
};
match decoder.decode(&config.input) { let result = decoder
Ok(result) => println!("{:?}", result), .decode(&config.input)
Err(e) => eprintln!("Error: {}", e), .with_context(|| format!("Failed to decode input: {}", config.input))?;
let json = serde_json::to_string_pretty(&result).expect("JSON serialization failed");
println!("{}", json);
Ok(())
} }
Ok(()) // TODO: Map decode result
} }
mod defaults {
use const_format::formatcp;
pub const DEC_SYSTEM_NAME: &str = "major_pl";
pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", DEC_SYSTEM_NAME);
pub const HELP_DEC_INPUT: &str = formatcp!("Text to decode");
} }

68
app/src/commands/encode.rs

@ -1,9 +1,4 @@
use applib::SystemEncoder;
use applib::sys_major::encoder::Encoder;
use applib::sys_major::{self as major, LenValueMap};
use serde::Deserialize; use serde::Deserialize;
use tracing::debug;
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand}; use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::{AppConfig, System}; use crate::config::{AppConfig, System};
@ -14,25 +9,22 @@ use async_trait::async_trait;
use config::ConfigBuilder; use config::ConfigBuilder;
use config::builder::DefaultState; use config::builder::DefaultState;
mod defaults {
use const_format::formatcp;
pub const ENC_SYSTEM_NAME: &str = "major_pl";
pub const HELP_ENC_SYSTEM: &str = formatcp!("System to use [default: {}]", ENC_SYSTEM_NAME);
pub const HELP_ENC_INPUT: &str = formatcp!("Number to encode");
}
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct Config { pub struct Config {
pub system: System, pub system: System,
pub input: String, pub input: String,
pub dict_name: String,
} }
#[derive(ClapArgs, Debug, Clone)] #[derive(ClapArgs, Debug, Clone)]
pub struct EncodeArgs { pub struct EncodeArgs {
#[arg(long, help = defaults::HELP_ENC_SYSTEM)] #[arg(short, long, help = defaults::HELP_ENC_SYSTEM)]
pub system: Option<String>, pub system: Option<String>,
#[arg(long, help = defaults::HELP_ENC_INPUT)] #[arg(short, long, help = defaults::HELP_ENC_DICT)]
pub dict_name: Option<String>,
#[arg(short, long, help = defaults::HELP_ENC_INPUT)]
pub input: String, pub input: String,
} }
@ -42,8 +34,9 @@ impl ConfigurableCommand for EncodeArgs {
builder: ConfigBuilder<DefaultState>, builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> { ) -> Result<ConfigBuilder<DefaultState>> {
builder builder
.set_default("encoder.system", defaults::ENC_SYSTEM_NAME)? .set_default("encode.system", defaults::ENC_SYSTEM_NAME)?
.set_default("encoder.input", "") .set_default("encode.dict_name", defaults::ENC_DICT_NAME)?
.set_default("encode.input", "")
.map_err(Into::into) .map_err(Into::into)
} }
@ -52,10 +45,14 @@ impl ConfigurableCommand for EncodeArgs {
builder: ConfigBuilder<DefaultState>, builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> { ) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder; let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("encoder.system", system.clone())?; if let Some(system) = &self.system {
builder = builder.set_override("encode.system", system.clone())?;
}
if let Some(dict_name) = &self.dict_name {
builder = builder.set_override("encode.dict_name", dict_name.clone())?;
} }
builder = builder.set_override("encoder.input", self.input.clone())?; builder = builder.set_override("encode.input", self.input.clone())?;
Ok(builder) Ok(builder)
} }
} }
@ -63,25 +60,13 @@ impl ConfigurableCommand for EncodeArgs {
#[async_trait] #[async_trait]
impl CommandExecutor for EncodeArgs { impl CommandExecutor for EncodeArgs {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config.encoder.as_ref().expect("Encoder config not set"); let config = config
let repo = container.create_dict_repo("demo_pl").await?; .encode
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Encoder config not set"))?;
debug!("Running encoder with config {:?}", config); let encoder = container.create_encoder(&config).await?;
let result = encoder.encode(&config.input);
let system_encoder: Box<dyn SystemEncoder> = match config.system {
System::MajorPl | System::MajorEn => {
let decoder = major::Decoder::new(match config.system {
System::MajorPl => major::rules_pl::get_rules(),
System::MajorEn => major::rules_en::get_rules(),
// _ => unreachable!(),
});
let stream = repo.stream_batches(100).await.unwrap();
let lvmap = LenValueMap::from_stream(stream, &decoder).await.unwrap();
Box::new(Encoder::new(lvmap))
}
};
let result = system_encoder.encode(&config.input);
match result { match result {
Ok(res) => { Ok(res) => {
@ -94,3 +79,12 @@ impl CommandExecutor for EncodeArgs {
Ok(()) Ok(())
} }
} }
mod defaults {
use const_format::formatcp;
pub const ENC_SYSTEM_NAME: &str = "major_pl";
pub const ENC_DICT_NAME: &str = "demo_pl";
pub const HELP_ENC_SYSTEM: &str = formatcp!("System to use [default: {}]", ENC_SYSTEM_NAME);
pub const HELP_ENC_INPUT: &str = formatcp!("Number to encode");
pub const HELP_ENC_DICT: &str = formatcp!("Dictionary to use [default: {}]", ENC_DICT_NAME);
}

9
app/src/commands/import_dict.rs

@ -1,7 +1,6 @@
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand}; use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::container::Container; use crate::container::Container;
use crate::defaults;
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use config::ConfigBuilder; use config::ConfigBuilder;
@ -62,3 +61,11 @@ impl CommandExecutor for ImportDictArgs {
Ok(()) Ok(())
} }
} }
mod defaults {
use const_format::formatcp;
pub const IMPORT_DICT_NAME: &str = "";
pub const IMPORT_DICT_PATH: &str = "";
pub const HELP_IMPORT_DICT_NAME: &str = formatcp!("Dictionary name");
pub const HELP_IMPORT_DICT_INPUT: &str = formatcp!("Dictionary file path");
}

81
app/src/commands/server.rs

@ -1,81 +0,0 @@
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use async_trait::async_trait;
use config::ConfigBuilder;
use config::builder::DefaultState;
use serde::Deserialize;
use tokio::signal;
use tracing::{info, warn};
#[derive(Debug, Deserialize, Clone)]
pub struct Config {
pub port: u16,
}
#[derive(ClapArgs, Debug, Clone)]
pub struct ServerArgs {
#[arg(short, long, help = defaults::HELP_PORT)]
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)
}
}
#[async_trait]
impl CommandExecutor for ServerArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> {
let config = config.server.as_ref().expect("Server config not set");
info!("Running server with config: {:#?}", config);
tokio::select! {
_ = server_loop() => {},
_ = wait_for_shutdown_signal() => {
info!("Shutting down server...");
}
}
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);
}
}
}
async fn server_loop() {
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
info!("Health check... ");
}
}

29
app/src/config.rs

@ -7,11 +7,9 @@ use serde::Deserialize;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct AppConfig { pub struct AppConfig {
#[serde(default)] #[serde(default)]
pub server: Option<server::Config>, pub decode: Option<decode::Config>,
#[serde(default)] #[serde(default)]
pub decoder: Option<decode::Config>, pub encode: Option<encode::Config>,
#[serde(default)]
pub encoder: Option<encode::Config>,
#[serde(default)] #[serde(default)]
pub import_dict: Option<import_dict::Config>, pub import_dict: Option<import_dict::Config>,
pub log_level: String, pub log_level: String,
@ -50,8 +48,6 @@ impl AppConfig {
} }
// TODO: move? // TODO: move?
use applib::sys_major::{self as major, LenValueMap};
use applib::{DictRepository, SystemDecoder, SystemEncoder};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
pub enum System { pub enum System {
@ -71,24 +67,3 @@ impl From<&str> for System {
} }
} }
} }
pub fn create_decoder(system: &System) -> Box<dyn SystemDecoder> {
match system {
System::MajorPl => Box::new(major::Decoder::new(major::rules_pl::get_rules())),
System::MajorEn => Box::new(major::Decoder::new(major::rules_en::get_rules())),
}
}
pub async fn create_encoder(system: &System, dict: &dyn DictRepository) -> Box<dyn SystemEncoder> {
// let decoder = create_decoder(&system);
let decoder = major::Decoder::new(match system {
System::MajorPl => major::rules_pl::get_rules(),
System::MajorEn => major::rules_en::get_rules(),
});
let stream = dict.stream_batches(100).await.unwrap(); // TODO
let lvmap = LenValueMap::from_stream(stream, &decoder).await.unwrap(); // TODO
match system {
System::MajorPl => Box::new(major::Encoder::new(lvmap)),
System::MajorEn => Box::new(major::Encoder::new(lvmap)),
}
}

39
app/src/container.rs

@ -4,6 +4,13 @@ use std::sync::Arc;
use applib::DictImporter; use applib::DictImporter;
use applib::DictRepository; use applib::DictRepository;
use applib::SqliteDictRepository; use applib::SqliteDictRepository;
use applib::SystemDecoder;
use applib::SystemEncoder;
use applib::sys_major as major;
use crate::commands::decode;
use crate::commands::encode;
use crate::config::System;
#[derive(Clone)] #[derive(Clone)]
pub struct Container; pub struct Container;
@ -26,4 +33,36 @@ impl Container {
dict_repo.use_dict(dict_name); dict_repo.use_dict(dict_name);
Ok(Arc::new(dict_repo)) Ok(Arc::new(dict_repo))
} }
pub fn create_decoder(
&self,
config: &decode::Config,
) -> anyhow::Result<Box<dyn SystemDecoder>> {
Ok(match config.system {
System::MajorPl => Box::new(major::Decoder::new(major::rules_pl::get_rules())),
System::MajorEn => Box::new(major::Decoder::new(major::rules_en::get_rules())),
})
}
pub async fn create_encoder(
&self,
config: &encode::Config,
) -> anyhow::Result<Box<dyn SystemEncoder>> {
let dict = self.create_dict_repo(&config.dict_name).await?;
let dec_config = decode::Config {
system: config.system.clone(),
input: String::new(),
};
let decoder = self.create_decoder(&dec_config)?;
let words_stream = dict.stream_batches(1000).await.unwrap();
let lvmap = major::LenValueMap::from_stream(words_stream, &(*decoder))
.await
.unwrap();
let encoder = major::Encoder::new(lvmap);
Ok(Box::new(encoder))
}
} }

13
app/src/defaults.rs

@ -1,13 +0,0 @@
pub const HOST: &str = "127.0.0.1";
pub const PORT: u16 = 8080;
pub const LOG_LEVEL: &str = "info";
pub const IMPORT_DICT_NAME: &str = "";
pub const IMPORT_DICT_PATH: &str = "";
use const_format::formatcp;
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_IMPORT_DICT_NAME: &str = formatcp!("Dictionary name");
pub const HELP_IMPORT_DICT_INPUT: &str = formatcp!("Dictionary file path");

1
app/src/main.rs

@ -2,7 +2,6 @@ mod app;
mod commands; mod commands;
mod config; mod config;
mod container; mod container;
mod defaults;
use anyhow::Result; use anyhow::Result;
use app::Application; use app::Application;

2
lib/src/common/entities.rs

@ -37,7 +37,7 @@ impl Deref for EncodedValue {
/// and dictionary words (reasonable length), we can use /// and dictionary words (reasonable length), we can use
/// u64 (20-digit number), but the whole input text can /// u64 (20-digit number), but the whole input text can
/// be longer than 20 digits, so we operate on String (<= 255). /// be longer than 20 digits, so we operate on String (<= 255).
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Clone, PartialEq, Eq)]
pub struct DecodedValue(String); pub struct DecodedValue(String);
impl DecodedValue { impl DecodedValue {

Loading…
Cancel
Save