summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs54
-rw-r--r--src/error.rs23
-rw-r--r--src/main.rs76
-rw-r--r--src/repo/mod.rs25
4 files changed, 83 insertions, 95 deletions
diff --git a/src/config.rs b/src/config.rs
deleted file mode 100644
index da65385..0000000
--- a/src/config.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use crate::TwinHError;
-use once_cell::sync::Lazy;
-use std::{env, error::Error, net::IpAddr, net::Ipv4Addr, net::SocketAddr};
-
-pub static CONFIG_INSTANCE: Lazy<Config> = Lazy::new(|| match Config::new() {
- Ok(c) => c,
- Err(e) => panic!("twinh: config error: {}", e),
-});
-
-#[derive(Clone, Debug)]
-pub struct Config {
- pub bind_addr: SocketAddr,
- pub db_path: String,
-}
-
-impl Default for Config {
- fn default() -> Self {
- Self {
- bind_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5353),
- db_path: String::from("/var/db/twinh"),
- }
- }
-}
-
-impl Config {
- fn new() -> Result<Self, Box<dyn Error>> {
- let mut args = env::args().skip(1);
-
- let db_path = args
- .next()
- .ok_or_else(|| TwinHError(String::from("database directory not provided")))?;
-
- let mut config = Config {
- bind_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5353),
- db_path,
- };
-
- while let Some(arg) = args.next() {
- match arg.as_str() {
- "--addr" => {
- let addr = args.next().unwrap_or_default().parse()?;
- config.bind_addr.set_ip(addr);
- }
- "--port" => {
- let port = args.next().unwrap_or_default().parse()?;
- config.bind_addr.set_port(port);
- }
- _ => {}
- };
- }
-
- Ok(config)
- }
-}
diff --git a/src/error.rs b/src/error.rs
index 943c3ec..ef0ef1d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,6 +1,9 @@
use bincode::Error as bincode_e;
+use hyper::Error as hyper_e;
use sled::Error as sled_e;
use std::fmt;
+use std::net::AddrParseError;
+use std::num::ParseIntError;
#[derive(Debug)]
pub struct TwinHError(pub String);
@@ -9,7 +12,7 @@ impl std::error::Error for TwinHError {}
impl std::fmt::Display for TwinHError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "Twin H-Power: {}", self.0)
+ write!(f, "twinh: {}", self.0)
}
}
@@ -24,3 +27,21 @@ impl From<bincode_e> for TwinHError {
Self(format!("(de)serialization error: {}", e))
}
}
+
+impl From<AddrParseError> for TwinHError {
+ fn from(e: AddrParseError) -> Self {
+ Self(format!("failed to parse addr: {}", e))
+ }
+}
+
+impl From<ParseIntError> for TwinHError {
+ fn from(e: ParseIntError) -> Self {
+ Self(format!("failed to parse port: {}", e))
+ }
+}
+
+impl From<hyper_e> for TwinHError {
+ fn from(e: hyper_e) -> Self {
+ Self(format!("server error: {}", e))
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 02fdc2e..0c7766a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,10 @@
-use crate::{config::CONFIG_INSTANCE, error::TwinHError};
+use crate::error::TwinHError;
use hyper::{
service::{make_service_fn, service_fn},
Server,
};
-use std::env;
+use std::{env, net::IpAddr, net::Ipv4Addr, net::SocketAddr};
-mod config;
mod error;
mod import;
mod models;
@@ -14,9 +13,19 @@ mod routes;
mod templates;
#[tokio::main]
-async fn main() -> Result<(), Box<dyn std::error::Error>> {
- // handle non-config args
- for arg in env::args().skip(1) {
+async fn main() -> Result<(), TwinHError> {
+ // print help if there are no arguments
+ let mut args = env::args().skip(1).peekable();
+ if args.peek().is_none() {
+ print_help();
+ return Ok(());
+ }
+
+ // set default bind addr
+ let mut bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5353);
+
+ // handle arguments and options
+ while let Some(arg) = args.next() {
match arg.as_str() {
"--create-db" => {
// create a fresh database and quit
@@ -25,34 +34,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
"--import" => {
// import CSV data into database
+ let _source = args
+ .next()
+ .ok_or_else(|| TwinHError(String::from("import source not provided")))?;
todo!();
}
- "--help" | "-h" => {
- // print help
- print!(
- "twinh: a home-grown classic car parts catalog\n\
- \nUsage: twinh <dir> [options]\n\
- <dir> your database directory (e.g. /var/db/twinh)\n\
- \nOptions:\n\
- --help | -h prints this message and exits\n\
- --addr an ip address to bind to (e.g. 127.0.0.1)\n\
- --port a port to bind to (e.g. 5353)\n\
- --create-db creates a fresh empty database; <dir> cannot exist yet\n\
- --import-cars imports CSV car data into the database\n\
- --import-parts imports CSV parts data into the database\n\
- "
- );
- return Ok(());
+ "--addr" => {
+ bind_addr.set_ip(args.next().unwrap_or_default().parse()?);
+ }
+ "--port" => {
+ bind_addr.set_port(args.next().unwrap_or_default().parse()?);
}
- unknown => {
- panic!("unknown option: {}", unknown);
+ _ => {
+ // if not the last argument (the database) then it's unknown
+ if args.peek().is_some() {
+ print_help();
+ return Ok(());
+ }
}
};
}
- // gather config
- let bind_addr = CONFIG_INSTANCE.bind_addr;
-
// create primary listener
let make_svc =
make_service_fn(move |_conn| async { Ok::<_, TwinHError>(service_fn(routes::router)) });
@@ -62,10 +64,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let graceful = server.with_graceful_shutdown(shutdown_signal());
// start and run until signal
- if let Err(e) = graceful.await {
- eprintln!("server error: {}", e);
- }
-
+ graceful.await?;
Ok(())
}
@@ -75,3 +74,18 @@ async fn shutdown_signal() {
.await
.expect("failed to install CTRL+C signal handler");
}
+
+fn print_help() {
+ print!(
+ "twinh: a home-grown classic car parts catalog\n\
+ \nUsage: twinh [options] <dir>\n\
+ <dir> your database directory (e.g. /var/db/twinh)\n\
+ \nOptions:\n\
+ --addr an ip address to bind to (e.g. 127.0.0.1)\n\
+ --port a port to bind to (e.g. 5353)\n\
+ --create-db creates a fresh empty database; <dir> cannot exist yet\n\
+ --import-cars imports CSV car data into the database\n\
+ --import-parts imports CSV parts data into the database\n\
+ "
+ );
+}
diff --git a/src/repo/mod.rs b/src/repo/mod.rs
index 45e9ce3..c7992c9 100644
--- a/src/repo/mod.rs
+++ b/src/repo/mod.rs
@@ -1,4 +1,3 @@
-use crate::config::CONFIG_INSTANCE;
use crate::error::TwinHError;
use crate::models::Car;
use crate::models::Part;
@@ -6,20 +5,28 @@ use bincode::deserialize;
use constants::*;
use once_cell::sync::Lazy;
use sled::{Config, Db};
+use std::env;
mod constants;
-static REPO_INSTANCE: Lazy<Db> = Lazy::new(|| {
- Config::default()
- .path(&CONFIG_INSTANCE.db_path)
- .temporary(true)
- .open()
- .expect("Couldn't open DB!")
+pub static DB_PATH_INSTANCE: Lazy<String> = Lazy::new(|| {
+ env::args()
+ .skip(1)
+ .last()
+ .expect("database directory not provided")
});
+static REPO_INSTANCE: Lazy<Db> =
+ Lazy::new(
+ || match Config::default().path(DB_PATH_INSTANCE.as_str()).open() {
+ Err(e) => panic!("failed to open database: {}", e),
+ Ok(db) => db,
+ },
+ );
+
pub fn create_demo_db() -> Result<(), TwinHError> {
let db = sled::Config::default()
- .path(&CONFIG_INSTANCE.db_path)
+ .path(DB_PATH_INSTANCE.as_str())
.create_new(true)
.open()?;
let cars_tree = db.open_tree(CARS_TREE)?;
@@ -28,7 +35,7 @@ pub fn create_demo_db() -> Result<(), TwinHError> {
pub fn create_new_db() -> Result<(), TwinHError> {
sled::Config::default()
- .path(&CONFIG_INSTANCE.db_path)
+ .path(DB_PATH_INSTANCE.as_str())
.create_new(true)
.open()?;
Ok(())