staticrocket 0.3.1

Simple http server for serving static content.
use std::{fs, path::Path};

use clap::{ArgMatches, Args, Command};

use qsu::{
  argp::{ArgParser, ArgsProc},
  installer::RegSvc,
  rt::SrvAppRt
};

use crate::err::Error;

/// Create a default Rocket.toml file for use with staticrocket.
#[derive(Debug, Args)]
struct GenConf {
  /// Overwrite Rocket.toml if one already exists.
  #[arg(short, long)]
  force: bool
}

/// Create an argument parser.
///
/// This function is needed (rather than just calling `ArgParser::new()`)
/// because the `make-config` subcommand needs to be added.
pub fn create<'cb>(
  svcname: &str,
  cb: &'cb mut dyn ArgsProc<AppErr = Error>
) -> ArgParser<'cb, Error> {
  // Create the "root" command line parser
  let cli = Command::new("")
    .name(env!("CARGO_PKG_NAME"))
    .about(env!("CARGO_PKG_DESCRIPTION"))
    .version(env!("CARGO_PKG_VERSION"));

  // Create "make-config" subcommand
  let mkc_subcmd = Command::new("make-config");
  let mkc_subcmd = GenConf::augment_args(mkc_subcmd);

  // Add make-config subcommand to "root" command line parser
  let cli = cli.subcommand(mkc_subcmd);

  ArgParser::with_cmd(svcname, cli, cb)
}

pub struct AppArgsProc {}

impl qsu::argp::ArgsProc for AppArgsProc {
  type AppErr = Error;

  /// Process an `register-service` subcommand.
  fn proc_inst(
    &mut self,
    _sub_m: &ArgMatches,
    regsvc: RegSvc
  ) -> Result<RegSvc, Self::AppErr> {
    // Use current working directory as the service's workdir
    let cwd = std::env::current_dir()?.to_str().unwrap().to_string();
    let desc = env!("CARGO_PKG_DESCRIPTION");

    let regsvc = regsvc
      .workdir(cwd)
      .netservice()
      .display_name("Rocket HTTP Server")
      .description(desc);

    // ToDo: Print a warning if Rocket.toml doesn't exist in current directory?
    Ok(regsvc)
  }

  /// Application call-back for subcommands that qsu doesn't handle itself.
  fn proc_other(
    &mut self,
    subcmd: &str,
    sub_m: &ArgMatches
  ) -> Result<(), Self::AppErr> {
    match subcmd {
      "make-config" => {
        const ROCKET_TOML: &str = include_str!("../Rocket.toml");

        let force = sub_m.get_flag("force");

        let fname = Path::new("Rocket.toml");
        if fname.exists() {
          if force {
            fs::remove_file(fname)?;
          } else {
            Err(qsu::Error::io("File 'Rocket.toml' already exists."))?;
          }
        }

        fs::write(fname, ROCKET_TOML)?;

        Ok(())
      }
      _ => {
        todo!();
      }
    }
  }

  fn build_apprt(&mut self) -> Result<SrvAppRt<Error>, Self::AppErr> {
    Ok(crate::app::create())
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :