add command line arguments

This commit is contained in:
2021-02-20 21:38:18 +01:00
parent 4e26080820
commit 3ba590b2f7
10 changed files with 147 additions and 35 deletions
+1
View File
@@ -26,6 +26,7 @@ itertools = "0.10.0"
json_dotpath = "1.0.3"
anyhow = "1.0.38"
thiserror = "1.0.24"
clap = "2"
tokio = { version="0.2.6", features=["full"] }
+68 -16
View File
@@ -7,18 +7,19 @@ extern crate thiserror;
use std::collections::HashMap;
use std::ops::Deref;
use std::path::PathBuf;
use actix_session::CookieSession;
use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web::{App, HttpResponse, HttpServer, web};
use actix_web_static_files;
use actix_web_static_files::ResourceFiles as StaticFiles;
use clap::Arg;
use log::LevelFilter;
use once_cell::sync::Lazy;
use rand::Rng;
use tera::Tera;
use yopa::insert::{InsertObj, InsertRel, InsertValue};
use yopa::{Storage, TypedValue};
use yopa::{Storage};
use crate::tera_ext::TeraExt;
@@ -101,25 +102,83 @@ pub(crate) static TERA: Lazy<Tera> = Lazy::new(|| {
type YopaStoreWrapper = web::Data<tokio::sync::RwLock<yopa::Storage>>;
const DEF_ADDRESS : &str = "127.0.0.1:8080";
#[actix_web::main]
async fn main() -> std::io::Result<()> {
simple_logging::log_to_stderr(LevelFilter::Debug);
let def_addr_help = format!("Set custom server address, default {}", DEF_ADDRESS);
let app = clap::App::new("yopa")
.arg(Arg::with_name("version")
.long("version")
.short("V")
.help("Show version and exit"))
.arg(Arg::with_name("verbose")
.short("v")
.multiple(true)
.help("Increase verbosity of logging"))
.arg(Arg::with_name("address")
.short("a")
.takes_value(true)
.help(&def_addr_help))
.arg(Arg::with_name("json")
.long("json")
.short("j")
.help("Use JSON storage format instead of binary"))
.arg(Arg::with_name("file")
.help("Database file to use"));
let matches = app.get_matches();
if matches.is_present("version") {
println!("yopa-web {}, using yopa {}", env!("CARGO_PKG_VERSION"), yopa::VERSION);
return Ok(());
}
simple_logging::log_to_stderr(match matches.occurrences_of("verbose") {
0 => LevelFilter::Warn,
1 => LevelFilter::Info,
2 => LevelFilter::Debug,
_ => LevelFilter::Trace,
});
debug!("Load Tera templates");
// Ensure the lazy ref is initialized early (to catch template bugs ASAP)
let _ = TERA.deref();
let yopa_store: YopaStoreWrapper = init_yopa()
let file = matches.value_of("file").unwrap_or("yopa-store.dat");
let file_path = if file.starts_with('/') {
std::env::current_dir()?.join(file)
} else {
PathBuf::from(file)
};
debug!("Using database file: {}", file_path.display());
let mut store = if matches.is_present("json") {
Storage::new_json(file_path)
} else {
Storage::new_bincode(file_path)
};
store.load()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let yopa_store: YopaStoreWrapper = web::Data::new(tokio::sync::RwLock::new(store));
let mut session_key = [0u8; 32];
rand::thread_rng().fill(&mut session_key);
trace!("Cookie session key: {:?}", session_key);
debug!("Session key: {:?}", session_key);
let server_address = matches.value_of("address").unwrap_or(DEF_ADDRESS);
println!("Starting web interface at http://{}", server_address);
HttpServer::new(move || {
let static_files =
StaticFiles::new("/static", included_static_files()).do_not_resolve_defaults();
debug!("Starting server thread");
App::new()
/* Middlewares */
.wrap(CookieSession::signed(&session_key).secure(false))
@@ -162,14 +221,7 @@ async fn main() -> std::io::Result<()> {
HttpResponse::NotFound().body("File or endpoint not found")
}))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
fn init_yopa() -> anyhow::Result<YopaStoreWrapper> {
let mut store = Storage::new_bincode(std::env::current_dir()?.join("yopa-store.dat"));
store.load()?;
Ok(web::Data::new(tokio::sync::RwLock::new(store)))
.bind(server_address)?
.run()
.await
}
+2 -5
View File
@@ -125,15 +125,12 @@ pub(crate) async fn update(
#[get("/model/object/delete/{id}")]
pub(crate) async fn delete(
id: web::Path<String>,
id: web::Path<ID>,
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await;
match wg.undefine_object(
id.parse()
.map_err(|e| actix_web::error::ErrorBadRequest(e))?,
) {
match wg.undefine_object(*id) {
Ok(om) => {
wg.persist().err_to_500()?;
debug!("Object model deleted, redirecting to root");
+6 -7
View File
@@ -13,7 +13,7 @@ use crate::TERA;
#[get("/model/property/create/{object_id}")]
pub(crate) async fn create_form(
object_id: web::Path<String>,
id: web::Path<ID>,
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<impl Responder> {
@@ -39,17 +39,16 @@ pub(crate) async fn create_form(
);
}
debug!("ID = {}", object_id);
debug!("ID = {}", id);
let object = {
let id = object_id.parse_or_bad_request()?;
debug!("Create property for ID={}", id);
if let Some(om) = rg.get_object_model(id) {
if let Some(om) = rg.get_object_model(*id) {
ObjectOrRelationModelDisplay {
id: om.id,
describe: format!("object model \"{}\"", om.name),
}
} else if let Some(rm) = rg.get_relation_model(id) {
} else if let Some(rm) = rg.get_relation_model(*id) {
ObjectOrRelationModelDisplay {
id: rm.id,
describe: format!("relation model \"{}\"", rm.name),
@@ -164,12 +163,12 @@ pub(crate) async fn create(
#[get("/model/property/delete/{id}")]
pub(crate) async fn delete(
id: web::Path<String>,
id: web::Path<ID>,
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await;
match wg.undefine_property(id.parse_or_bad_request()?) {
match wg.undefine_property(*id) {
Ok(rm) => {
wg.persist().err_to_500()?;
debug!("Property deleted, redirecting to root");
+4 -4
View File
@@ -19,7 +19,7 @@ pub(crate) struct RelationModelDisplay<'a> {
#[get("/model/relation/create/{object_id}")]
pub(crate) async fn create_form(
object_id: web::Path<String>,
object_id: web::Path<ID>,
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<impl Responder> {
@@ -47,7 +47,7 @@ pub(crate) async fn create_form(
}
let object = rg
.get_object_model(object_id.parse_or_bad_request()?)
.get_object_model(*object_id)
.ok_or_else(|| actix_web::error::ErrorNotFound("No such source object"))?;
let mut models: Vec<_> = rg.get_object_models().collect();
@@ -112,12 +112,12 @@ pub(crate) struct ObjectOrRelationModelDisplay {
#[get("/model/relation/delete/{id}")]
pub(crate) async fn delete(
id: web::Path<String>,
id: web::Path<ID>,
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await;
match wg.undefine_relation(id.parse_or_bad_request()?) {
match wg.undefine_relation(*id) {
Ok(rm) => {
wg.persist().err_to_500()?;
debug!("Relation deleted, redirecting to root");
-2
View File
@@ -499,8 +499,6 @@ pub(crate) async fn update(
store: crate::YopaStoreWrapper,
session: Session,
) -> actix_web::Result<HttpResponse> {
warn!("{:?}", form);
let mut wg = store.write().await;
let form = form.into_inner();
let name = form.name.clone();
+1 -1
View File
@@ -1,5 +1,5 @@
use actix_web::http::header::IntoHeaderValue;
use actix_web::{HttpResponse, ResponseError, Error};
use actix_web::{HttpResponse, ResponseError};
use std::fmt::{Debug, Display};
use std::str::FromStr;
use yopa::StorageError;