add command line arguments

master
Ondřej Hruška 4 years ago
parent 4e26080820
commit 3ba590b2f7
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 63
      Cargo.lock
  2. BIN
      yopa-store.dat
  3. 1
      yopa-web/Cargo.toml
  4. 80
      yopa-web/src/main.rs
  5. 7
      yopa-web/src/routes/models/object.rs
  6. 13
      yopa-web/src/routes/models/property.rs
  7. 8
      yopa-web/src/routes/models/relation.rs
  8. 2
      yopa-web/src/routes/objects.rs
  9. 2
      yopa-web/src/utils.rs
  10. 2
      yopa/src/lib.rs

63
Cargo.lock generated

@ -369,6 +369,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.38" version = "1.0.38"
@ -386,6 +395,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@ -612,6 +632,21 @@ dependencies = [
"generic-array 0.14.4", "generic-array 0.14.4",
] ]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]] [[package]]
name = "const_fn" name = "const_fn"
version = "0.4.5" version = "0.4.5"
@ -2009,6 +2044,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.4.0" version = "2.4.0"
@ -2048,6 +2089,15 @@ dependencies = [
"unic-segment", "unic-segment",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.24" version = "1.0.24"
@ -2375,6 +2425,12 @@ version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.1"
@ -2413,6 +2469,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.2"
@ -2588,6 +2650,7 @@ dependencies = [
"actix-web", "actix-web",
"actix-web-static-files", "actix-web-static-files",
"anyhow", "anyhow",
"clap",
"heck", "heck",
"include_dir", "include_dir",
"itertools", "itertools",

Binary file not shown.

@ -26,6 +26,7 @@ itertools = "0.10.0"
json_dotpath = "1.0.3" json_dotpath = "1.0.3"
anyhow = "1.0.38" anyhow = "1.0.38"
thiserror = "1.0.24" thiserror = "1.0.24"
clap = "2"
tokio = { version="0.2.6", features=["full"] } tokio = { version="0.2.6", features=["full"] }

@ -7,18 +7,19 @@ extern crate thiserror;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Deref; use std::ops::Deref;
use std::path::PathBuf;
use actix_session::CookieSession; 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;
use actix_web_static_files::ResourceFiles as StaticFiles; use actix_web_static_files::ResourceFiles as StaticFiles;
use clap::Arg;
use log::LevelFilter; use log::LevelFilter;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rand::Rng; use rand::Rng;
use tera::Tera; use tera::Tera;
use yopa::insert::{InsertObj, InsertRel, InsertValue}; use yopa::{Storage};
use yopa::{Storage, TypedValue};
use crate::tera_ext::TeraExt; 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>>; type YopaStoreWrapper = web::Data<tokio::sync::RwLock<yopa::Storage>>;
const DEF_ADDRESS : &str = "127.0.0.1:8080";
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { 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) // Ensure the lazy ref is initialized early (to catch template bugs ASAP)
let _ = TERA.deref(); 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))?; .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]; let mut session_key = [0u8; 32];
rand::thread_rng().fill(&mut session_key); rand::thread_rng().fill(&mut session_key);
trace!("Cookie session key: {:?}", session_key);
let server_address = matches.value_of("address").unwrap_or(DEF_ADDRESS);
debug!("Session key: {:?}", session_key); println!("Starting web interface at http://{}", server_address);
HttpServer::new(move || { HttpServer::new(move || {
let static_files = let static_files =
StaticFiles::new("/static", included_static_files()).do_not_resolve_defaults(); StaticFiles::new("/static", included_static_files()).do_not_resolve_defaults();
debug!("Starting server thread");
App::new() App::new()
/* Middlewares */ /* Middlewares */
.wrap(CookieSession::signed(&session_key).secure(false)) .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") HttpResponse::NotFound().body("File or endpoint not found")
})) }))
}) })
.bind("127.0.0.1:8080")? .bind(server_address)?
.run() .run()
.await .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)))
}

@ -125,15 +125,12 @@ pub(crate) async fn update(
#[get("/model/object/delete/{id}")] #[get("/model/object/delete/{id}")]
pub(crate) async fn delete( pub(crate) async fn delete(
id: web::Path<String>, id: web::Path<ID>,
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<impl Responder> { ) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await; let mut wg = store.write().await;
match wg.undefine_object( match wg.undefine_object(*id) {
id.parse()
.map_err(|e| actix_web::error::ErrorBadRequest(e))?,
) {
Ok(om) => { Ok(om) => {
wg.persist().err_to_500()?; wg.persist().err_to_500()?;
debug!("Object model deleted, redirecting to root"); debug!("Object model deleted, redirecting to root");

@ -13,7 +13,7 @@ use crate::TERA;
#[get("/model/property/create/{object_id}")] #[get("/model/property/create/{object_id}")]
pub(crate) async fn create_form( pub(crate) async fn create_form(
object_id: web::Path<String>, id: web::Path<ID>,
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<impl Responder> { ) -> 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 object = {
let id = object_id.parse_or_bad_request()?;
debug!("Create property for ID={}", id); 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 { ObjectOrRelationModelDisplay {
id: om.id, id: om.id,
describe: format!("object model \"{}\"", om.name), 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 { ObjectOrRelationModelDisplay {
id: rm.id, id: rm.id,
describe: format!("relation model \"{}\"", rm.name), describe: format!("relation model \"{}\"", rm.name),
@ -164,12 +163,12 @@ pub(crate) async fn create(
#[get("/model/property/delete/{id}")] #[get("/model/property/delete/{id}")]
pub(crate) async fn delete( pub(crate) async fn delete(
id: web::Path<String>, id: web::Path<ID>,
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<impl Responder> { ) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await; let mut wg = store.write().await;
match wg.undefine_property(id.parse_or_bad_request()?) { match wg.undefine_property(*id) {
Ok(rm) => { Ok(rm) => {
wg.persist().err_to_500()?; wg.persist().err_to_500()?;
debug!("Property deleted, redirecting to root"); debug!("Property deleted, redirecting to root");

@ -19,7 +19,7 @@ pub(crate) struct RelationModelDisplay<'a> {
#[get("/model/relation/create/{object_id}")] #[get("/model/relation/create/{object_id}")]
pub(crate) async fn create_form( pub(crate) async fn create_form(
object_id: web::Path<String>, object_id: web::Path<ID>,
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<impl Responder> { ) -> actix_web::Result<impl Responder> {
@ -47,7 +47,7 @@ pub(crate) async fn create_form(
} }
let object = rg 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"))?; .ok_or_else(|| actix_web::error::ErrorNotFound("No such source object"))?;
let mut models: Vec<_> = rg.get_object_models().collect(); let mut models: Vec<_> = rg.get_object_models().collect();
@ -112,12 +112,12 @@ pub(crate) struct ObjectOrRelationModelDisplay {
#[get("/model/relation/delete/{id}")] #[get("/model/relation/delete/{id}")]
pub(crate) async fn delete( pub(crate) async fn delete(
id: web::Path<String>, id: web::Path<ID>,
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<impl Responder> { ) -> actix_web::Result<impl Responder> {
let mut wg = store.write().await; let mut wg = store.write().await;
match wg.undefine_relation(id.parse_or_bad_request()?) { match wg.undefine_relation(*id) {
Ok(rm) => { Ok(rm) => {
wg.persist().err_to_500()?; wg.persist().err_to_500()?;
debug!("Relation deleted, redirecting to root"); debug!("Relation deleted, redirecting to root");

@ -499,8 +499,6 @@ pub(crate) async fn update(
store: crate::YopaStoreWrapper, store: crate::YopaStoreWrapper,
session: Session, session: Session,
) -> actix_web::Result<HttpResponse> { ) -> actix_web::Result<HttpResponse> {
warn!("{:?}", form);
let mut wg = store.write().await; let mut wg = store.write().await;
let form = form.into_inner(); let form = form.into_inner();
let name = form.name.clone(); let name = form.name.clone();

@ -1,5 +1,5 @@
use actix_web::http::header::IntoHeaderValue; use actix_web::http::header::IntoHeaderValue;
use actix_web::{HttpResponse, ResponseError, Error}; use actix_web::{HttpResponse, ResponseError};
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::str::FromStr; use std::str::FromStr;
use yopa::StorageError; use yopa::StorageError;

@ -37,6 +37,8 @@ mod serde_map_as_list;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub const VERSION : &'static str = env!("CARGO_PKG_VERSION");
/// Stupid storage with naive inefficient file persistence /// Stupid storage with naive inefficient file persistence
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Storage { pub struct Storage {

Loading…
Cancel
Save