From 17598ab89b4fb6fbdbb8190c902c243de1e689db Mon Sep 17 00:00:00 2001 From: librelois <elois@ifee.fr> Date: Sat, 16 Nov 2019 19:19:26 +0100 Subject: [PATCH] [feat] gva: configure host & port --- bin/dunitrust-server/src/cli.rs | 10 ++++ lib/core/conf/src/lib.rs | 8 ++++ lib/core/module/src/lib.rs | 2 + lib/modules/gva/Cargo.toml | 3 +- lib/modules/gva/src/errors.rs | 26 +++++++++++ lib/modules/gva/src/lib.rs | 80 ++++++++++++++++++++++---------- lib/modules/gva/src/webserver.rs | 18 +++++-- 7 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 lib/modules/gva/src/errors.rs diff --git a/bin/dunitrust-server/src/cli.rs b/bin/dunitrust-server/src/cli.rs index 3fb1136e..20f451bf 100644 --- a/bin/dunitrust-server/src/cli.rs +++ b/bin/dunitrust-server/src/cli.rs @@ -25,6 +25,7 @@ use durs_core::commands::{ }; use durs_core::errors::DursCoreError; use durs_core::DursCore; +use durs_gva::{GvaModule, GvaOpt}; use durs_network::cli::sync::SyncOpt; use durs_ws2p_v1_legacy::{WS2POpt, WS2Pv1Module}; use log::Level; @@ -68,6 +69,12 @@ impl ExecutableModuleCommand for DursCliOpt { env!("CARGO_PKG_VERSION"), ) } + DursCliSubCommand::Gva(module_opts) => DursCore::execute_module_command::<GvaModule>( + options, + module_opts, + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + ), _ => unreachable!(), } } @@ -156,6 +163,9 @@ pub enum DursCliSubCommand { /// Synchronize #[structopt(name = "sync", setting(structopt::clap::AppSettings::ColoredHelp))] SyncOpt(SyncOpt), + /// GVA module subcommand + #[structopt(name = "gva", setting(structopt::clap::AppSettings::ColoredHelp))] + Gva(GvaOpt), /// WS2P1 module subcommand #[structopt(name = "ws2p1", setting(structopt::clap::AppSettings::ColoredHelp))] Ws2p1(WS2POpt), diff --git a/lib/core/conf/src/lib.rs b/lib/core/conf/src/lib.rs index a1be9932..9141d218 100644 --- a/lib/core/conf/src/lib.rs +++ b/lib/core/conf/src/lib.rs @@ -279,6 +279,14 @@ impl DursConfTrait for DuRsConf { DuRsConf::V2 { .. } => 2, } } + fn get_currency(&self) -> CurrencyName { + match *self { + DuRsConf::V1(ref conf_v1) => conf_v1.currency.clone(), + DuRsConf::V2 { + ref global_conf, .. + } => global_conf.currency.clone(), + } + } fn set_currency(&mut self, new_currency: CurrencyName) { match *self { DuRsConf::V1(ref mut conf_v1) => conf_v1.currency = new_currency, diff --git a/lib/core/module/src/lib.rs b/lib/core/module/src/lib.rs index 71400044..2d10c83f 100644 --- a/lib/core/module/src/lib.rs +++ b/lib/core/module/src/lib.rs @@ -136,6 +136,8 @@ pub trait DursConfTrait: fn my_node_id(&self) -> u32 { self.get_global_conf().my_node_id() } + /// Get currency name + fn get_currency(&self) -> CurrencyName; /// Set currency fn set_currency(&mut self, new_currency: CurrencyName); /// Change module conf diff --git a/lib/modules/gva/Cargo.toml b/lib/modules/gva/Cargo.toml index b6f91e4c..ea24ecd6 100644 --- a/lib/modules/gva/Cargo.toml +++ b/lib/modules/gva/Cargo.toml @@ -18,6 +18,7 @@ durs-conf = { path = "../../core/conf" } durs-message = { path = "../../core/message" } durs-module = { path = "../../core/module" } durs-network = { path = "../../core/network" } +durs-network-documents = { path = "../../dunp/network-documents" } dubp-common-doc = { path = "../../dubp/common-doc"} #, version = "0.1.0" } durs-common-tools = { path = "../../tools/common-tools" } dubp-currency-params = { path = "../../dubp/currency-params" } @@ -31,6 +32,6 @@ log = "0.4.8" serde = "1.0.102" serde_derive = "1.0.102" serde_json = "1.0.41" -structopt= "0.2.18" +structopt= "0.3.4" [features] diff --git a/lib/modules/gva/src/errors.rs b/lib/modules/gva/src/errors.rs new file mode 100644 index 00000000..4c10a5ac --- /dev/null +++ b/lib/modules/gva/src/errors.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Gva errors + +use failure::Fail; + +#[derive(Debug, Fail)] +/// GVA error +pub enum GvaError { + /// Invalid host + #[fail(display = "Invalid host")] + InvalidHost, +} diff --git a/lib/modules/gva/src/lib.rs b/lib/modules/gva/src/lib.rs index ce417cdf..1e71e6f6 100644 --- a/lib/modules/gva/src/lib.rs +++ b/lib/modules/gva/src/lib.rs @@ -44,9 +44,11 @@ extern crate structopt; extern crate juniper; mod context; +mod errors; mod schema; mod webserver; +use crate::errors::GvaError; use dubp_currency_params::CurrencyName; use durs_common_tools::fatal_error; use durs_common_tools::traits::merge::Merge; @@ -60,6 +62,7 @@ use durs_module::{ //use durs_module::*; use durs_network::events::NetworkEvent; +use durs_network_documents::host::Host; use std::ops::Deref; use std::sync::mpsc; @@ -68,30 +71,43 @@ use std::time::{Duration, SystemTime}; static MODULE_NAME: &str = "gva"; +static DEFAULT_HOST: &str = "127.0.0.1"; +const DEFAULT_PORT: u16 = 10_901; + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Gva Module Configuration pub struct GvaConf { - test_fake_conf_field: String, + host: String, + port: u16, } impl Default for GvaConf { fn default() -> Self { GvaConf { - test_fake_conf_field: String::from("default value"), + host: DEFAULT_HOST.to_owned(), + port: DEFAULT_PORT, } } } +impl std::fmt::Display for GvaConf { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "host: {}\nport: {}", self.host, self.port,) + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Gva user Configuration pub struct GvaUserConf { - test_fake_conf_field: Option<String>, + host: Option<String>, + port: Option<u16>, } impl Merge for GvaUserConf { fn merge(self, other: Self) -> Self { GvaUserConf { - test_fake_conf_field: self.test_fake_conf_field.or(other.test_fake_conf_field), + host: self.host.or(other.host), + port: self.port.or(other.port), } } } @@ -110,14 +126,15 @@ pub enum GvaMsg { } #[derive(StructOpt, Debug, Clone)] -#[structopt( - name = "gva", - raw(setting = "structopt::clap::AppSettings::ColoredHelp") -)] +#[structopt(name = "gva", setting(structopt::clap::AppSettings::ColoredHelp))] /// Gva subcommand options pub struct GvaOpt { - /// Change test conf fake field - pub new_conf_field: String, + /// Change GVA API host listen + #[structopt(long = "host", parse(try_from_str = Host::parse))] + pub host: Option<Host>, + #[structopt(long = "port")] + /// Change GVA API port listen + pub port: Option<u16>, } #[derive(Debug, Clone)] @@ -164,37 +181,50 @@ impl DursModule<DuRsConf, DursMsg> for GvaModule { let mut conf = GvaConf::default(); if let Some(ref module_user_conf) = module_user_conf { - if let Some(ref test_fake_conf_field) = module_user_conf.test_fake_conf_field { - conf.test_fake_conf_field = test_fake_conf_field.to_owned(); + if let Some(ref host) = module_user_conf.host { + conf.host = host.to_owned(); + } + if let Some(port) = module_user_conf.port { + conf.port = port; } } Ok((conf, module_user_conf)) } fn exec_subcommand( - _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, + soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, - module_conf: Self::ModuleConf, - _module_user_conf: Option<Self::ModuleUserConf>, + _module_conf: Self::ModuleConf, + module_user_conf: Option<Self::ModuleUserConf>, subcommand_args: Self::ModuleOpt, ) -> Option<Self::ModuleUserConf> { - let new_gva_conf = GvaUserConf { - test_fake_conf_field: Some(subcommand_args.new_conf_field.to_owned()), - }; - info!( - "Succesfully exec skeleton subcommand whit terminal name : {} and conf={:?}!", - subcommand_args.new_conf_field, module_conf - ); - Some(new_gva_conf) + let new_gva_user_conf = GvaUserConf { + host: subcommand_args.host.map(|h| h.to_string()), + port: subcommand_args.port, + } + .merge(module_user_conf.unwrap_or_default()); + match Self::generate_module_conf( + Some(&soft_meta_datas.conf.get_currency()), + &soft_meta_datas.conf.get_global_conf(), + Some(new_gva_user_conf.clone()), + ) { + Ok((new_gva_conf, _)) => println!("New GVA configuration:\n{}", new_gva_conf), + Err(e) => println!("Fail to change GVA confguration : {:?}", e), + } + + Some(new_gva_user_conf) } fn start( soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, - _conf: Self::ModuleConf, + conf: Self::ModuleConf, router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>, ) -> Result<(), failure::Error> { let _start_time = SystemTime::now(); + // Check conf validity + let host = Host::parse(&conf.host).map_err(|_| GvaError::InvalidHost)?; + // Instanciate Gva module datas let datas = GvaModuleDatas { child_threads: Vec::new(), @@ -262,7 +292,7 @@ impl DursModule<DuRsConf, DursMsg> for GvaModule { let smd: SoftwareMetaDatas<DuRsConf> = soft_meta_datas.clone(); let router_sender_clone = router_sender.clone(); thread::spawn(move || { - if let Err(e) = webserver::start_web_server(&smd) { + if let Err(e) = webserver::start_web_server(&smd, host, conf.port) { error!("GVA http web server error : {} ", e); } else { info!("GVA http web server stop.") diff --git a/lib/modules/gva/src/webserver.rs b/lib/modules/gva/src/webserver.rs index 0f1379fe..89606c6b 100644 --- a/lib/modules/gva/src/webserver.rs +++ b/lib/modules/gva/src/webserver.rs @@ -20,6 +20,8 @@ use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use durs_common_tools::fatal_error; use durs_conf::DuRsConf; use durs_module::SoftwareMetaDatas; +use durs_network_documents::host::Host; +use durs_network_documents::url::Url; use futures::future::Future; use juniper::http::graphiql::graphiql_source; use juniper::http::GraphQLRequest; @@ -27,7 +29,7 @@ use std::net::SocketAddr; use std::sync::Arc; fn graphiql() -> HttpResponse { - let html = graphiql_source("http://127.0.0.1:3000/graphql"); + let html = graphiql_source("/graphql"); HttpResponse::Ok() .content_type("text/html; charset=utf-8") .body(html) @@ -50,9 +52,15 @@ fn graphql( }) } -pub fn start_web_server(soft_meta_datas: &SoftwareMetaDatas<DuRsConf>) -> std::io::Result<()> { - info!("GVA web server start."); - let addr: SocketAddr = ([127, 0, 0, 1], 3000).into(); +pub fn start_web_server( + soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, + host: Host, + port: u16, +) -> std::io::Result<()> { + info!("GVA web server start..."); + + let addrs: Vec<SocketAddr> = + Url::from_host_port_path(host, port, None).to_listenable_addr("http")?; // Create Juniper schema let schema = std::sync::Arc::new(create_schema()); @@ -73,6 +81,6 @@ pub fn start_web_server(soft_meta_datas: &SoftwareMetaDatas<DuRsConf>) -> std::i .service(web::resource("/graphql").route(web::post().to_async(graphql))) .service(web::resource("/graphiql").route(web::get().to(graphiql))) }) - .bind(addr)? + .bind(&addrs[..])? .run() } -- GitLab