21 changed files with 191 additions and 64 deletions
@ -0,0 +1,5 @@
|
||||
pub mod args; |
||||
pub mod commands; |
||||
pub mod defaults; |
||||
pub mod handlers; |
||||
pub mod traits; |
||||
@ -1,4 +1,5 @@
|
||||
use crate::cli::{ConfigurableCommand, defaults}; |
||||
use crate::cli::defaults; |
||||
use crate::cli::traits::ConfigurableCommand; |
||||
use anyhow::Result; |
||||
use clap::{Args as ClapArgs, Parser, Subcommand}; |
||||
use config::ConfigBuilder; |
||||
@ -0,0 +1,22 @@
|
||||
use applib::application::config::DecoderConfig; |
||||
use applib::core::sys_major::decoder::Decoder; |
||||
use applib::core::sys_major::{self as major, LenValueMap}; |
||||
use applib::core::traits::SystemDecoder; |
||||
use applib::system::System; |
||||
use std::sync::Arc; |
||||
|
||||
pub async fn run(config: DecoderConfig) { |
||||
let decoder: Box<dyn SystemDecoder> = match config.system { |
||||
System::MajorPl => Box::new(Decoder::new(major::rules_pl::get_rules())), |
||||
System::MajorEn => Box::new(Decoder::new(major::rules_en::get_rules())), |
||||
// _ => {
|
||||
// eprintln!("Unknown system: {:?}", config.system);
|
||||
// return;
|
||||
// }
|
||||
}; |
||||
|
||||
match decoder.decode(&config.input) { |
||||
Ok(result) => println!("{:?}", result), |
||||
Err(e) => eprintln!("Error: {}", e), |
||||
} |
||||
} |
||||
@ -0,0 +1,36 @@
|
||||
use applib::application::config::EncoderConfig; |
||||
use applib::core::sys_major::encoder::Encoder; |
||||
use applib::core::sys_major::{self as major, LenValueMap}; |
||||
use applib::core::traits::{DictRepository, SystemEncoder}; |
||||
use applib::system::System; |
||||
use tracing::debug; |
||||
|
||||
pub async fn run(config: EncoderConfig, dict: &dyn DictRepository) { |
||||
debug!("Running encoder with config {:?}", config); |
||||
|
||||
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 = dict.stream_batches(100).await.unwrap(); |
||||
let lvmap = LenValueMap::from_stream(stream, &decoder).await.unwrap(); |
||||
Box::new(Encoder::new(lvmap)) |
||||
} // _ => {
|
||||
// eprintln!("Unknown system: {:?}", config.system);
|
||||
// return;
|
||||
// }
|
||||
}; |
||||
|
||||
let result = system_encoder.encode(&config.input); |
||||
|
||||
match result { |
||||
Ok(res) => { |
||||
let json = serde_json::to_string_pretty(&res).expect("JSON serialization failed"); |
||||
println!("{}", json); |
||||
} |
||||
Err(e) => eprintln!("Error encoding: {:?}", e), |
||||
} |
||||
} |
||||
@ -0,0 +1,12 @@
|
||||
use anyhow::Result; |
||||
use applib::DictImporter; |
||||
use applib::application::config::ImportDictConfig; |
||||
|
||||
pub async fn run(config: ImportDictConfig, importer: DictImporter) -> Result<()> { |
||||
// Importer expects an impl DictSource
|
||||
// We need to create a DictSource from the path
|
||||
use applib::infrastructure::json_file_dict_source::JsonFileDictSource; |
||||
let source = JsonFileDictSource::new(&config.path)?; |
||||
importer.import(source).await?; |
||||
Ok(()) |
||||
} |
||||
@ -0,0 +1,6 @@
|
||||
use applib::application::config::ServerConfig; |
||||
use std::future::Future; |
||||
|
||||
pub async fn run(config: ServerConfig, signal: impl Future<Output = ()> + Send + 'static) { |
||||
applib::presentation::server::run(config, signal).await; |
||||
} |
||||
@ -0,0 +1,81 @@
|
||||
use crate::cli::args::{Command, DecodeArgs, EncodeArgs, ImportDictArgs, ServerArgs}; |
||||
use crate::cli::commands; |
||||
use crate::cli::traits::ConfigurableCommand; |
||||
use crate::config::AppConfig; |
||||
use crate::container::Container; |
||||
use anyhow::Result; |
||||
use async_trait::async_trait; |
||||
use tokio::signal; |
||||
use tracing::{info, warn}; |
||||
|
||||
#[async_trait] |
||||
pub trait CommandExecutor { |
||||
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()>; |
||||
} |
||||
|
||||
// AppCommand must be dyn-compatible. ConfigurableCommand is already dyn-compatible.
|
||||
// CommandExecutor is dyn-compatible because of #[async_trait].
|
||||
pub trait AppCommand: ConfigurableCommand + CommandExecutor {} |
||||
|
||||
impl<T: ConfigurableCommand + CommandExecutor> AppCommand for T {} |
||||
|
||||
pub fn resolve_command(command: &Command) -> &dyn AppCommand { |
||||
match command { |
||||
Command::Server(args) => args, |
||||
Command::Decode(args) => args, |
||||
Command::Encode(args) => args, |
||||
Command::ImportDict(args) => args, |
||||
} |
||||
} |
||||
|
||||
#[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"); |
||||
commands::server::run(config.clone(), wait_for_shutdown_signal()).await; |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl CommandExecutor for DecodeArgs { |
||||
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> { |
||||
let config = config.decoder.as_ref().expect("Decoder config not set"); |
||||
commands::decode::run(config.clone()).await; |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl CommandExecutor for EncodeArgs { |
||||
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { |
||||
let config = config.encoder.as_ref().expect("Encoder config not set"); |
||||
let repo = container.create_dict_repo("demo_pl").await?; |
||||
commands::encode::run(config.clone(), repo.as_ref()).await; |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl CommandExecutor for ImportDictArgs { |
||||
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { |
||||
let config = config |
||||
.import_dict |
||||
.as_ref() |
||||
.expect("ImportDict config not set"); |
||||
let importer = container.create_dict_importer(&config.name).await?; |
||||
commands::import_dict::run(config.clone(), 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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,14 @@
|
||||
use anyhow::Result; |
||||
pub use config::ConfigBuilder; |
||||
pub use config::builder::DefaultState; |
||||
|
||||
pub trait ConfigurableCommand { |
||||
fn apply_defaults( |
||||
&self, |
||||
builder: ConfigBuilder<DefaultState>, |
||||
) -> Result<ConfigBuilder<DefaultState>>; |
||||
fn apply_overrides( |
||||
&self, |
||||
builder: ConfigBuilder<DefaultState>, |
||||
) -> Result<ConfigBuilder<DefaultState>>; |
||||
} |
||||
@ -1,10 +1,10 @@
|
||||
pub mod application; |
||||
mod core; |
||||
pub mod core; |
||||
pub mod infrastructure; |
||||
mod presentation; |
||||
pub mod presentation; |
||||
|
||||
pub use self::application::config; |
||||
pub use self::application::services::DictImporter; |
||||
pub use self::core::system; |
||||
pub use self::core::traits; |
||||
pub use self::presentation::cli; |
||||
// pub use self::presentation::cli; // Removed as we are deleting it
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
use crate::application::config::DecoderConfig; |
||||
use crate::core::system; |
||||
use tracing::debug; |
||||
|
||||
pub async fn run(config: DecoderConfig) { |
||||
debug!("Running decoder with config {:?}", config); |
||||
let decoder = system::create_decoder(&config.system); |
||||
let result = decoder.decode(&config.input).unwrap(); |
||||
println!("{}", result.as_str()); |
||||
} |
||||
@ -1,13 +0,0 @@
|
||||
use crate::application::config::EncoderConfig; |
||||
use crate::core::{DictRepository, system}; |
||||
use tracing::debug; |
||||
|
||||
pub async fn run(config: EncoderConfig, dict: &dyn DictRepository) { |
||||
debug!("Running encoder with config {:?}", config); |
||||
let encoder = system::create_encoder(&config.system, dict).await; |
||||
let result = encoder.encode(&config.input).unwrap(); |
||||
|
||||
let json = serde_json::to_string_pretty(&result).expect("JSON serialization failed"); |
||||
|
||||
println!("{}", json); |
||||
} |
||||
@ -1,27 +0,0 @@
|
||||
use crate::application::{config::ImportDictConfig, services::DictImporter}; |
||||
use crate::infrastructure::json_file_dict_source::JsonFileDictSource; |
||||
use tracing::{debug, error, info}; |
||||
|
||||
pub async fn run(config: ImportDictConfig, importer: DictImporter) -> Result<(), anyhow::Error> { |
||||
debug!("Importing dict with config {:?}", config); |
||||
|
||||
info!( |
||||
"Starting import of dictionary '{}' from file '{}'", |
||||
config.name, config.path |
||||
); |
||||
|
||||
// Create the JSON file source (will auto-generate IDs starting from 1)
|
||||
let source = JsonFileDictSource::new(&config.path)?; |
||||
|
||||
// Perform the import (this will call create() first)
|
||||
match importer.import(source).await { |
||||
Ok(()) => { |
||||
info!("Successfully imported dictionary '{}'", config.name); |
||||
Ok(()) |
||||
} |
||||
Err(e) => { |
||||
error!("Failed to import dictionary '{}': {}", config.name, e); |
||||
Err(e) |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue