From 548e93a323a5769bf3ea2794512433e68f9175bc Mon Sep 17 00:00:00 2001 From: librelois <elois@ifee.fr> Date: Sat, 16 Nov 2019 23:32:50 +0100 Subject: [PATCH] [feat] gva: add queries node summary and block by number --- lib/modules-lib/bc-db-reader/src/blocks.rs | 6 +- lib/modules-lib/bc-db-reader/src/lib.rs | 2 +- lib/modules/gva/Cargo.toml | 4 +- lib/modules/gva/resources/schema.gql | 24 +++++ lib/modules/gva/src/context.rs | 22 +++- lib/modules/gva/src/schema.rs | 118 +++++++++++++-------- lib/modules/gva/src/schema/block.rs | 83 +++++++++++++++ lib/modules/gva/src/webserver.rs | 2 +- 8 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 lib/modules/gva/src/schema/block.rs diff --git a/lib/modules-lib/bc-db-reader/src/blocks.rs b/lib/modules-lib/bc-db-reader/src/blocks.rs index b280dee7..d23a149f 100644 --- a/lib/modules-lib/bc-db-reader/src/blocks.rs +++ b/lib/modules-lib/bc-db-reader/src/blocks.rs @@ -100,7 +100,7 @@ pub fn get_block<DB: DbReadable>( blockstamp: Blockstamp, ) -> Result<Option<DbBlock>, DbError> { db.read(|r| { - let opt_dal_block = get_dal_block_in_local_blockchain(db, r, blockstamp.id)?; + let opt_dal_block = get_db_block_in_local_blockchain(db, r, blockstamp.id)?; if opt_dal_block.is_none() { get_fork_block(db, r, blockstamp) } else { @@ -145,11 +145,11 @@ pub fn get_block_in_local_blockchain<DB: DbReadable, R: DbReader>( r: &R, block_number: BlockNumber, ) -> Result<Option<BlockDocument>, DbError> { - Ok(get_dal_block_in_local_blockchain(db, r, block_number)?.map(|dal_block| dal_block.block)) + Ok(get_db_block_in_local_blockchain(db, r, block_number)?.map(|dal_block| dal_block.block)) } /// Get block in local blockchain -pub fn get_dal_block_in_local_blockchain<DB: DbReadable, R: DbReader>( +pub fn get_db_block_in_local_blockchain<DB: DbReadable, R: DbReader>( db: &DB, r: &R, block_number: BlockNumber, diff --git a/lib/modules-lib/bc-db-reader/src/lib.rs b/lib/modules-lib/bc-db-reader/src/lib.rs index 9364d67a..00297e27 100644 --- a/lib/modules-lib/bc-db-reader/src/lib.rs +++ b/lib/modules-lib/bc-db-reader/src/lib.rs @@ -39,9 +39,9 @@ pub use durs_dbs_tools::kv_db::{ KvFileDbRead as DbReadable, KvFileDbRoHandler as BcDbRo, KvFileDbSchema, KvFileDbStoreType, KvFileDbValue as DbValue, Readable as DbReader, }; +pub use durs_dbs_tools::DbError; use constants::*; -use durs_dbs_tools::DbError; use maplit::hashmap; use std::path::Path; diff --git a/lib/modules/gva/Cargo.toml b/lib/modules/gva/Cargo.toml index ea24ecd6..894509e3 100644 --- a/lib/modules/gva/Cargo.toml +++ b/lib/modules/gva/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" path = "src/lib.rs" [dependencies] -proc-macro2 = "1.0.6" actix-web = "1.0.8" dubp-block-doc = { path = "../../dubp/block-doc"} #, version = "0.1.0" } durs-bc-db-reader = { path = "../../modules-lib/bc-db-reader" } @@ -22,13 +21,14 @@ 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" } +chrono = "0.4.9" failure = "0.1.5" futures = "0.1" futures-cpupool = "0.1" juniper = "0.14.0" - juniper-from-schema = "0.5.0" log = "0.4.8" +proc-macro2 = "1.0.6" serde = "1.0.102" serde_derive = "1.0.102" serde_json = "1.0.41" diff --git a/lib/modules/gva/resources/schema.gql b/lib/modules/gva/resources/schema.gql index 8115701e..d9147a4f 100644 --- a/lib/modules/gva/resources/schema.gql +++ b/lib/modules/gva/resources/schema.gql @@ -5,16 +5,40 @@ schema { } type Query { + node: Node! @juniper(ownership: "owned") current: Block @juniper(ownership: "owned") + block(number: Int!): Block @juniper(ownership: "owned") } type Mutation { noop: Boolean! } +################################# +# NODE types +################################# + +type Summary { + software: String! @juniper(infallible: true, ownership: "owned") + version: String! @juniper(infallible: true, ownership: "owned") +} + + +type Node { + summary: Summary! @juniper(infallible: true) +} + +################################# +# Block type +################################# + +scalar DateTimeUtc @juniper(with_time_zone: false) + type Block { version: Int! currency: String! issuer: String! number: Int! + hash: String!, + commonTime: DateTimeUtc! } diff --git a/lib/modules/gva/src/context.rs b/lib/modules/gva/src/context.rs index 29955f75..6e27d678 100644 --- a/lib/modules/gva/src/context.rs +++ b/lib/modules/gva/src/context.rs @@ -22,23 +22,37 @@ static mut CONTEXT: Option<Context> = None; #[derive(Debug)] pub struct Context { db: BcDbRo, + software_name: &'static str, + software_version: &'static str, } impl juniper::Context for Context {} impl Context { - pub fn new(db: BcDbRo) -> Self { - Context { db } + pub fn new(db: BcDbRo, software_name: &'static str, software_version: &'static str) -> Self { + Context { + db, + software_name, + software_version, + } } pub fn get_db(&self) -> &BcDbRo { &self.db } + + pub fn get_software_name(&self) -> &'static str { + &self.software_name + } + + pub fn get_software_version(&self) -> &'static str { + &self.software_version + } } -pub fn init(db: BcDbRo) { +pub fn init(db: BcDbRo, soft_name: &'static str, soft_version: &'static str) { unsafe { - CONTEXT.replace(Context::new(db)); + CONTEXT.replace(Context::new(db, soft_name, soft_version)); } } diff --git a/lib/modules/gva/src/schema.rs b/lib/modules/gva/src/schema.rs index 8f2ee9f1..842a3873 100644 --- a/lib/modules/gva/src/schema.rs +++ b/lib/modules/gva/src/schema.rs @@ -12,13 +12,15 @@ // // 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/>. -// -// model and resolvers implementation +// ! model and resolvers implementation + +mod block; + +use self::block::Block; use crate::context::Context; -use dubp_block_doc::block::BlockDocumentTrait; -use dubp_common_doc::traits::Document; -use durs_bc_db_reader::BcDbRo; +use dubp_common_doc::BlockNumber; +use durs_bc_db_reader::{BcDbRo, DbError, DbReadable}; use juniper::Executor; use juniper::FieldResult; use juniper_from_schema::graphql_schema_from_file; @@ -28,61 +30,85 @@ graphql_schema_from_file!("resources/schema.gql"); pub struct Query; -pub struct Block { - version: i32, - currency: String, - issuer: String, - number: i32, +pub struct Summary { + software: &'static str, + version: &'static str, +} + +pub struct Node { + summary: Summary, +} + +fn db_err_to_juniper_err(e: DbError) -> juniper::FieldError { + juniper::FieldError::from(format!("Db error: {:?}", e)) } impl QueryFields for Query { + fn field_node( + &self, + executor: &Executor<'_, Context>, + _trail: &QueryTrail<'_, Node, Walked>, + ) -> FieldResult<Node> { + Ok(Node { + summary: Summary { + software: executor.context().get_software_name(), + version: executor.context().get_software_version(), + }, + }) + } fn field_current( &self, - _executor: &Executor<'_, Context>, + executor: &Executor<'_, Context>, _trail: &QueryTrail<'_, Block, Walked>, ) -> FieldResult<Option<Block>> { - let db: &BcDbRo = &_executor.context().get_db(); - let current_blockstamp = durs_bc_db_reader::current_meta_datas::get_current_blockstamp(db); - - match current_blockstamp { - Ok(option) => match option { - Some(v) => { - let current_block = durs_bc_db_reader::blocks::get_block(db, v); - match current_block { - Ok(current_block_option) => match current_block_option { - Some(block) => Ok(Some(Block { - version: block.block.version() as i32, - currency: block.block.currency().to_string(), - issuer: block.block.issuers()[0].to_string(), - number: block.block.number().0 as i32, - })), - None => Ok(None), - }, - Err(_e) => Err(juniper::FieldError::from("No current block available")), - } - } - None => Ok(None), - }, - Err(_e) => Err(juniper::FieldError::from("No current block available")), - } - } -} + let db: &BcDbRo = &executor.context().get_db(); -impl BlockFields for Block { - fn field_version(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> { - Ok(&self.version) + db.read(|r| { + if let Some(current_blockstamp) = + durs_bc_db_reader::current_meta_datas::get_current_blockstamp_(db, r)? + { + block::get_block(db, r, current_blockstamp.id) + } else { + Ok(None) + } + }) + .map_err(db_err_to_juniper_err) } + fn field_block( + &self, + executor: &Executor<'_, Context>, + _trail: &QueryTrail<'_, Block, Walked>, + number: i32, + ) -> FieldResult<Option<Block>> { + let db: &BcDbRo = &executor.context().get_db(); + + let block_number = if number >= 0 { + BlockNumber(number as u32) + } else { + return Err(juniper::FieldError::from("Block number must be positive.")); + }; - fn field_currency(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> { - Ok(&self.currency) + db.read(|r| block::get_block(db, r, block_number)) + .map_err(|e| juniper::FieldError::from(format!("Db error: {:?}", e))) } +} - fn field_issuer(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> { - Ok(&self.issuer) +impl NodeFields for Node { + fn field_summary( + &self, + _executor: &Executor<'_, Context>, + _trail: &QueryTrail<'_, Summary, Walked>, + ) -> &Summary { + &self.summary } +} - fn field_number(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> { - Ok(&self.number) +impl SummaryFields for Summary { + fn field_software(&self, _executor: &Executor<'_, Context>) -> String { + self.software.to_owned() + } + fn field_version(&self, _executor: &Executor<'_, Context>) -> String { + self.version.to_owned() } } diff --git a/lib/modules/gva/src/schema/block.rs b/lib/modules/gva/src/schema/block.rs new file mode 100644 index 00000000..b155e8d5 --- /dev/null +++ b/lib/modules/gva/src/schema/block.rs @@ -0,0 +1,83 @@ +// 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/>. + +// ! Block model and resolvers + +use crate::context::Context; +use chrono::NaiveDateTime; +use dubp_block_doc::block::BlockDocumentTrait; +use dubp_common_doc::traits::Document; +use dubp_common_doc::BlockNumber; +use durs_bc_db_reader::{BcDbRo, DbError, DbReader}; +use durs_common_tools::fatal_error; +use juniper::{Executor, FieldResult}; + +pub struct Block { + version: i32, + currency: String, + issuer: String, + number: i32, + hash: String, + common_time: NaiveDateTime, +} + +impl super::BlockFields for Block { + fn field_version(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> { + Ok(&self.version) + } + + fn field_currency(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> { + Ok(&self.currency) + } + + fn field_issuer(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> { + Ok(&self.issuer) + } + + fn field_number(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> { + Ok(&self.number) + } + + fn field_hash(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> { + Ok(&self.hash) + } + + fn field_common_time(&self, _executor: &Executor<'_, Context>) -> FieldResult<&NaiveDateTime> { + Ok(&self.common_time) + } +} + +pub fn get_block<R: DbReader>( + db: &BcDbRo, + r: &R, + block_number: BlockNumber, +) -> Result<Option<Block>, DbError> { + durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(db, r, block_number).map( + |block_opt| { + block_opt.map(|db_block| Block { + version: db_block.block.version() as i32, + currency: db_block.block.currency().to_string(), + issuer: db_block.block.issuers()[0].to_string(), + number: db_block.block.number().0 as i32, + hash: db_block + .block + .hash() + .unwrap_or_else(|| fatal_error!("DbBlock without hash.")) + .to_string(), + common_time: NaiveDateTime::from_timestamp(db_block.block.common_time() as i64, 0), + }) + }, + ) +} diff --git a/lib/modules/gva/src/webserver.rs b/lib/modules/gva/src/webserver.rs index 89606c6b..fe065674 100644 --- a/lib/modules/gva/src/webserver.rs +++ b/lib/modules/gva/src/webserver.rs @@ -68,7 +68,7 @@ pub fn start_web_server( // Instanciate the context let db_path = durs_conf::get_blockchain_db_path(soft_meta_datas.profile_path.clone()); if let Ok(db) = durs_bc_db_reader::open_db_ro(&std::path::Path::new(&db_path)) { - context::init(db); + context::init(db, soft_meta_datas.soft_name, soft_meta_datas.soft_version); } else { fatal_error!("GVA: fail to open DB."); }; -- GitLab