mymq 0.1.0

Broker and message queues
Documentation
use arbitrary::Unstructured;
use log::info;
use rand::{rngs::StdRng, seq::SliceRandom};
use structopt::StructOpt;

use std::{io, path, result};

mod arbitr;
mod dump;
mod list;
mod show;
mod start;

#[derive(Clone, StructOpt)]
pub struct Opt {
    #[structopt(long = "config")]
    config_loc: Option<path::PathBuf>,

    #[structopt(short = "v")]
    v: bool,

    #[structopt(long = "vv")]
    vv: bool,

    #[structopt(long = "log-mod", default_value = "")]
    log_mod: String,

    #[structopt(long = "force-color")]
    force_color: bool,

    #[structopt(long = "seed")]
    seed: Option<u64>,

    #[structopt(subcommand)]
    subcmd: SubCommand,
}

#[derive(Clone, StructOpt)]
pub enum SubCommand {
    Start(start::Start),
    Dump(dump::Dump),
    List(list::List),
    Arbitr(arbitr::Arbitr),
    Show(show::Show),
}

pub type Result<T> = result::Result<T, String>;

fn main() {
    let opts = parse_cmd_line();

    setup_logging(&opts);
    info!("verbosity level {:?}", opts.to_verbosity());

    let res = match &opts.subcmd {
        SubCommand::Start(_) => start::run(opts),
        SubCommand::Dump(_) => dump::run(opts),
        SubCommand::List(_) => list::run(opts),
        SubCommand::Arbitr(_) => arbitr::run(opts),
        SubCommand::Show(_) => show::run(opts),
    };

    res.map_err(|e| println!("error: {}", e)).ok();
}

fn parse_cmd_line() -> Opt {
    Opt::from_args()
}

use env_logger::{fmt::Target, Builder, WriteStyle};
use log::Level;
use std::io::Write;
fn setup_logging(opts: &Opt) {
    let verbosity = opts.to_verbosity();
    let opts = opts.clone();
    Builder::from_default_env()
        .parse_default_env()
        .target(Target::Stdout)
        .format(move |f, r| {
            let file = r.file().clone().unwrap();
            if file.len() > 0 && !file.contains(&opts.log_mod) {
                return Ok(());
            }

            let target = r.target();
            match target {
                "0" | "1" | "2" if target <= verbosity.as_str() => log_format(f, r),
                "0" | "1" | "2" => Ok(()),
                _ => log_format(f, r),
            }
        })
        .write_style(WriteStyle::Auto)
        .init();
}

use env_logger::fmt::{Color, Formatter};
fn log_format(f: &mut Formatter, r: &log::Record<'_>) -> io::Result<()> {
    let mut level_style = f.style();
    match r.level() {
        Level::Error => level_style.set_color(Color::Red).set_bold(false),
        Level::Warn => level_style.set_color(Color::Yellow).set_bold(false),
        Level::Info => level_style.set_color(Color::Blue).set_bold(false),
        Level::Debug => level_style.set_color(Color::Magenta).set_bold(false),
        Level::Trace => level_style.set_color(Color::Cyan).set_bold(false),
    };
    let mut mod_style = f.style();
    mod_style.set_color(Color::Green).set_bold(false);
    let file = {
        let file = path::Path::new(r.file().clone().unwrap()).file_stem().unwrap();
        file.to_str().unwrap()
    };
    let loc = mod_style.value(format!("{}:{}", file, r.line().unwrap()));
    writeln!(
        f,
        "{} [{:5}] [{:>13}] {}",
        chrono::Local::now().format("%Y-%m-%dT%H:%M:%S%.3f%Z"),
        level_style.value(r.level()),
        loc,
        r.args()
    )
}

impl Opt {
    fn to_verbosity(&self) -> String {
        if self.v {
            "1"
        } else if self.vv {
            "2"
        } else {
            "0"
        }
        .to_string()
    }
}

pub fn new_unstructured<'a>(
    rng: &mut StdRng,
    bytes: &'a mut Vec<u8>,
) -> Unstructured<'a> {
    bytes.shuffle(rng);
    Unstructured::new(bytes.as_slice())
}