diff --git a/frontend/examples/csv-import/csv_import.rs b/frontend/examples/csv-import/csv_import.rs new file mode 100644 index 0000000..8a544ad --- /dev/null +++ b/frontend/examples/csv-import/csv_import.rs @@ -0,0 +1,58 @@ +/// Commandline program testing csv imports +use log::{info, trace, warn}; +use serde::Deserialize; +use std::{ + error::Error, + io, + process, + thread, + time::{Duration, Instant}}; + +mod parse_args; + +#[derive(Debug, Deserialize)] +struct Environment { + test_lang: String, +} + +#[derive(Debug, Deserialize)] +pub struct CsvImportRecord { + // dion => Allianz Dion: 1 + // policy_code => Policy Typ: "AS" + // policy_number => Versicherungsscheinnummer: "1515735810" + pub dion: String, + pub policy_code: String, + pub policy_number: u32, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + use parse_args::parse_args; + + use std::net::ToSocketAddrs; + use std::process; + use std::sync::Arc; + + use viperus::Viperus; + + // initialize logger + env_logger::init(); + info!("Commencing the proxy!"); + + // initialize viperus structure + let mut v = Viperus::new(); + + // parse commandline arguments + info!(target: "csv_import", "parsing commandline args"); + parse_args(&mut v)?; + trace!(target: "Viperus", "Config results: {:?}", v); + + // create a new NextCloudTalk client + let config = matches.value_of("config").unwrap_or("advotracker.conf"); + let csv_import = matches.value_of("import").unwrap_or("allianz.txt"); + //let username = matches.value_of("username").unwrap_or("nctalkbot"); + //let password = matches.value_of("password").unwrap_or("botpassword"); + let verbose = matches.occurrences_of("verbose"); + + Ok(()) +} diff --git a/frontend/examples/csv-import/csv_import_bak.rs b/frontend/examples/csv-import/csv_import_bak.rs new file mode 100644 index 0000000..7ec275b --- /dev/null +++ b/frontend/examples/csv-import/csv_import_bak.rs @@ -0,0 +1,94 @@ +/* advotracker infrastructure. + * + * Copyright 2020 Ralf Zerres + * SPDX-License-Identifier: (0BSD or MIT) + */ + +// Rust nightly supports procedural macros! +//#![feature(proc_macro)] +//#![deny(rust_2018_idioms)] + +use dotenv::dotenv; +use locales::t; +use serde::Deserialize; + +use std::env; +use std::error::Error; +use std::io; +use std::process; + +use tracing::{debug, trace, Level}; + +#[derive(Deserialize, Debug)] +struct Environment { + test_lang: String, +} + +#[derive(Debug, Deserialize)] +pub struct CsvImportRecord { + // dion => Allianz Dion: 1 + // policy_code => Policy Typ: "AS" + // policy_number => Versicherungsscheinnummer: "1515735810" + pub dion: String, + pub policy_code: String, + pub policy_number: u32, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + // the YAML file is found relative to the current file + //use clap_v3::{load_yaml, App}; + use clap::{load_yaml, App}; + + let yaml = load_yaml!("cli.yml"); + //let matches = App::from_yaml(yaml).get_matches(); + let matches = App::from_yaml(yaml) + .name(clap::crate_name!()) + .version(clap::crate_version!()) + .author(clap::crate_authors!()) + .about(clap::crate_description!()) + .get_matches(); + + // Gets the option value if supplied by user, otherwise set defaults + let config = matches.value_of("config").unwrap_or("advotracker.conf"); + let csv_import = matches.value_of("import").unwrap_or("allianz.txt"); + //let username = matches.value_of("username").unwrap_or("nctalkbot"); + //let password = matches.value_of("password").unwrap_or("botpassword"); + let verbose = matches.occurrences_of("verbose"); + + if verbose > 0 { + println!("{}: runtime parameters", clap::crate_name!()); + println!("config_file: '{}'", config); + println!("csv_import: '{}'", csv_import); + println!("verbosity level: {}", matches.occurrences_of("verbose")); + } + + if verbose > 1 { + println!("\nEnvironment:"); + for (key, value) in env::vars() { + println!("{}={}", key, value); + } + } + + Ok(()) +} + +/// import from csv format (Standard in) +fn import() -> Result<(), Box> { + // Build the CSV reader and iterate over each record. + let mut csv_reader = csv::Reader::from_reader(io::stdin()); + for result in csv_reader.deserialize() { + // The iterator yields Result, so we check the + // error here. + let record: CsvImportRecord = result?; + println!("{:?}", record); + } + Ok(()) +} + +fn main() { + if let Err(err) = import() { + println!("error running CSV-Import: {}", err); + process::exit(1); + } +} diff --git a/frontend/examples/csv-import/locales/main.json b/frontend/examples/csv-import/locales/main.json new file mode 100644 index 0000000..b6caee8 --- /dev/null +++ b/frontend/examples/csv-import/locales/main.json @@ -0,0 +1,78 @@ +{ + "err.lang.not_found": { + "de_DE.UTF-8": "Konnte Sprachkode nicht auslesen", + "de": "Konnte Sprachkode nicht auslesen", + "en": "Couldn't read LANG" + }, + "err.user.not_found": { + "fr": "Utilisateur introuvable: $email, $id", + "de-DE.UTF-8": "Anwender nicht gefunden: $email, $id", + "de": "Anwender nicht gefunden: $email, $id", + "en": "User not found: $email, $id" + }, + "main.started": { + "de_DE.UTF-8": "Programmlogik starten", + "de": "Programmlogik starten", + "en": "Program logic started" + }, + "main.finished": { + "de_DE.UTF-8": "Programmlogik beendet", + "de": "Programmlogik beendet", + "en": "Program logic finished" + }, + "parse.arguments": { + "de_DE.UTF-8": "Programmargumente prüfen", + "de": "Programmargumente prüfen", + "en": "Parsing arguments" + }, + "parse.environment": { + "de_DE.UTF-8": "Umgebungsvariablen prüfen", + "de": "Umgebungsvariablen prüfen", + "en": "Parsing environment" + }, + "parse.results": { + "de_DE.UTF-8": "Ergebnisse der Konfigurations-Parameterprüfung", + "de": "Ergebnisse der Konfigurationsparameterprüfung", + "en": "Config parsing results" + }, + "config.name": { + "de_DE.UTF-8": "Konfigurationswert für", + "de": "Konfigurationswert für", + "en": "Config Value for" + }, + "config.name.lang": { + "de_DE.UTF-8": "Sprach-Code", + "de": "Sprach-Code", + "en": "Language code" + }, + "config.name.verbositylevel": { + "de_DE.UTF-8": "Ausgabe-Ebene", + "de": "Ausgabe-Ebene", + "en": "verbosity level" + }, + "config.name.environment": { + "de_DE.UTF-8": "Umgebungsvariablen", + "de": "Umgebungsvariablen", + "en": "environment" + }, + "config.name.configfile": { + "de_DE.UTF-8": "Konfigurations-Datei", + "de": "Konfigurations-Datei", + "en": "config file" + }, + "config.name.dbdriver": { + "de_DE.UTF-8": "Datenbank-Treiber", + "de": "Datenbank-Treiber", + "en": "database driver" + }, + "state.started": { + "de_DE.UTF-8": "gestartet", + "de": "gestartet", + "en": "started" + }, + "state.finished": { + "de_DE.UTF-8": "beendet", + "de": "beended", + "en": "finished" + } +} diff --git a/frontend/examples/csv-import/main.rs b/frontend/examples/csv-import/main.rs new file mode 100644 index 0000000..2c73dbe --- /dev/null +++ b/frontend/examples/csv-import/main.rs @@ -0,0 +1,114 @@ +/// Commandline program testing csv imports +use serde::Deserialize; +use std::env; +use std::{ + error::Error, + io, +// process, +// thread, + // time::{Duration, Instant} +}; +use tracing::{debug, trace, Level}; + +mod parse_args; + +#[derive(Debug, Deserialize)] +struct Environment { + test_lang: String, +} + +#[derive(Debug, Deserialize)] +pub struct CsvImportRecord { + // dion => Allianz Dion: 1 + // policy_code => Policy Typ: "AS" + // policy_number => Versicherungsscheinnummer: "1515735810" + pub dion: String, + pub policy_code: String, + pub policy_number: u32, +} + +/// import from csv format (Standard in) +fn import() -> Result<(), Box> { + // Build the CSV reader and iterate over each record. + let mut csv_reader = csv::Reader::from_reader(io::stdin()); + for result in csv_reader.deserialize() { + // The iterator yields Result, so we check the + // error here. + let record: CsvImportRecord = result?; + println!("{:?}", record); + } + Ok(()) +} + +fn main() -> Result<(), Box> { + use dotenv::dotenv; + use parse_args::parse_args; + use locales::t; + //use std::process; + //use std::sync::Arc; + use tracing_subscriber::fmt; + use viperus::Viperus; + + // initialize the tracing subsystem + // a drop in replacement for classical logging + // reference: https://tokio.rs/blog/2019-08-tracing/ + let span = tracing::span!(Level::TRACE, "csv-import"); + let _enter = span.enter(); + let subscriber = fmt::Subscriber::builder() + .with_env_filter("csv-import=trace") + .finish(); + + // initialize logger + //env_logger::init(); + //info!("Commencing the import Test-Run!"); + + tracing::subscriber::with_default(subscriber, || { + // get system environment + let mut lang = env::var("LANG").unwrap_or("en".to_string()); + let mut res = t!("parse.environment", lang); + let mut state = t!("state.started", lang); + trace!(target: "csv-import", message = ?res, state = ?state); + //debug!(message = ?res, state = ?state); + trace!(target: "csv-import", environment = "system", lang = ?lang); + + // get testing environment (.env) + dotenv().ok(); + match envy::from_env::() { + Ok(environment) => { + if environment.test_lang != lang { lang = environment.test_lang; } + }, + Err(e) => { debug!(target: "csv-import", "{}", e); } + } + res = t!("parse.environment", lang); + trace!(target: "csv-import", environment = "envy", lang = ?lang); + state = t!("state.finished", lang); + trace!(target: "csv-import", message = ?res, state = ?state); + + // initialize viperus structure + let mut v = Viperus::new(); + + // parse commandline arguments + res = t!("parse.arguments", lang); + state = t!("state.started", lang); + trace!(target: "csv-import", process = ?res, state = ?state); + + let _ = parse_args(&mut v); + state = t!("state.finished", lang); + trace!(target: "csv-import", process = ?res, state = ?state); + //trace!(target: "Viperus", "Config results: {:?}", v); + + // Starting the program logic + res = t!("main.started", lang); + state = t!("state.started", lang); + trace!(target: "csv-import", process = ?res, state = ?state); + + // import the given import file + let csv_file = v.get::("import_file").unwrap(); + + state = t!("state.finished", lang); + res = t!("main.finished", lang); + trace!(target: "csv-import", process = ?res, state = ?state); + }); + + Ok(()) +} diff --git a/frontend/examples/csv-import/parse_args.rs b/frontend/examples/csv-import/parse_args.rs new file mode 100644 index 0000000..7f60109 --- /dev/null +++ b/frontend/examples/csv-import/parse_args.rs @@ -0,0 +1,151 @@ +use viperus::Viperus; + +/// The given Viperus structure will be muted according to the +/// processed default, environment and commandline arguments +pub fn parse_args(v: &mut Viperus) -> Result<(), Box> { + //use log::{debug, info, trace, warn}; + use log::trace; + use std::env; + + if cfg!(feature = "fmt-clap") { + trace!(target: "Viperus", "Viperus feature 'fmt-clap' enabled."); + println!("Using feature fmt-clap"); + } + + // preset default key/value pairs (lowest priority) + v.add_default("config_file", String::from("csv_import.ron")); + v.add_default("import_file", String::from("allianz.txt")); + //v.add_default("username", String::from("nctalkbot")); + //v.add_default("password", String::from("botpassword")); + v.add_default("verbose", 0); + + // parse CLI commandline arguments with clap + use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg}; + + // CLI arguments are defined inline + let matches = App::new("nctalkproxyd") + .name(crate_name!()) + .version(crate_version!()) + .author(crate_authors!()) + .about(crate_description!()) + .after_help("Test: Versicherungsnummern-Import Allianz DirectCall") + .template( + "\ + {bin} v{version} +{about} + +{all-args} + +(C) 2020 {author} +{after-help}", + ) + .arg( + Arg::with_name("configFile") + .short("c") + .long("configFile") + .value_name("FILE") + .help("Select a config file") + .takes_value(true), + ) + .arg( + Arg::with_name("importFile") + .short("i") + .long("importFile") + //.value_name("FILE") + .help("Select source file for the csv-import") + .takes_value(true), + ) + // .arg( + // Arg::with_name("username") + // .short("u") + // .long("username") + // .help("Sets username") + // .takes_value(true), + // ) + // .arg( + // Arg::with_name("password") + // .short("P") + // .long("password") + // .help("Sets password") + // .takes_value(true), + // ) + .arg( + Arg::with_name("verbose") + .short("v") + .long("verbose") + .help("Sets verbosity level") + .multiple(true), + ) + .get_matches(); + + if matches.occurrences_of("verbose") > 0 { + // clap is using i64, viperus i32 + let n = matches.occurrences_of("verbose") as i32; + v.add("verbose", n); + } + + // preset the prefix for relevant environment variables ("ADVOTRACKER_") + let mut env_prefix: String = crate_name!().to_uppercase(); + env_prefix.push_str("_"); + v.set_env_prefix(&env_prefix); + + // respect dotenv environment (e.g for testing) + // -> overwrites the preset default values + println!( + "RUST_LOG={}", + dotenv::var("RUST_LOG").unwrap_or_else(|_| String::from("None")) + ); + + // enable caching and automatic update of environment values + if cfg!(feature = "fmt-cache") { + v.cache(true); + } + if cfg!(feature = "fmt-env") { + v.automatic_env(true); + } + + // load user selected call arguments + // -> overwrites values given via environment variables + v.load_clap(matches)?; + + // bond the clap names to camel_case rust variable names + v.bond_clap("configFile", "config_file"); + v.bond_clap("importFile", "import_file"); + //v.bond_clap("username", "username"); + //v.bond_clap("password", "password"); + v.bond_clap("verbose", "verbose"); + + trace!("verbose {:?}", v.get::("verbose").unwrap()); + if v.get::("verbose").unwrap() > 0 { + println!( + "config_file: {:?}", + v.get::("config_file").unwrap_or_default() + ); + println!( + "import_file: {:?}", + v.get::("import_file").unwrap_or_default() + ); + // println!( + // "username: {:?}", + // v.get::("username").unwrap_or_default() + // ); + // println!( + // "password: {:?}", + // v.get::("password").unwrap_or_default() + // ); // only for testing now + + println!( + "verbosity level: {:?}", + v.get::("verbose").unwrap_or_default() + ); + } + + if v.get::("verbose").unwrap() > 1 { + println!("\nEnvironment:"); + for (key, value) in env::vars() { + println!("{}={}", key, value); + } + } + + Ok(()) +}