diff --git a/cxs/libcxs/Cargo.toml b/cxs/libcxs/Cargo.toml index 6b8cbc5f4f..9d3c6e5663 100644 --- a/cxs/libcxs/Cargo.toml +++ b/cxs/libcxs/Cargo.toml @@ -17,3 +17,4 @@ rand = "0.3" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +config = "0.6" diff --git a/cxs/libcxs/include/cxs.h b/cxs/libcxs/include/cxs.h index 990c2a6fc6..bfbc26b1f1 100644 --- a/cxs/libcxs/include/cxs.h +++ b/cxs/libcxs/include/cxs.h @@ -44,7 +44,7 @@ typedef struct { * Initialize the SDK */ -cxs_error_t cxs_init(); +cxs_error_t cxs_init(const char *config_path); /** diff --git a/cxs/libcxs/src/api/cxs.rs b/cxs/libcxs/src/api/cxs.rs index 953cef8f09..ac59bbb3a9 100644 --- a/cxs/libcxs/src/api/cxs.rs +++ b/cxs/libcxs/src/api/cxs.rs @@ -5,22 +5,42 @@ use api::CxsStatus; use utils::cstring::CStringUtils; use utils::{pool, wallet}; use utils::error; -use connection::build_connection; -use connection::connect; -use connection::to_string; -use connection::get_state; -use connection::release; -use std::ffi::CString; +use settings; +use connection::{build_connection, connect, to_string, get_state, release}; #[no_mangle] -pub extern fn cxs_init (pool_name:*const c_char, - config_name:*const c_char, - wallet_name:*const c_char, - wallet_type:*const c_char) -> u32 { - check_useful_c_str!(pool_name,1001); - check_useful_c_str!(config_name,1001); - check_useful_c_str!(wallet_name,1001); - check_useful_c_str!(wallet_type,1001); +pub extern fn cxs_init (config_path:*const c_char) -> u32 { + + settings::set_defaults(); + + if !config_path.is_null() { + check_useful_c_str!(config_path,error::UNKNOWN_ERROR.code_num); + + if settings::process_config_file(&config_path) != error::SUCCESS.code_num { + return error::UNKNOWN_ERROR.code_num; + } + } + + let config_name = match settings::get_config_value(settings::CONFIG_POOL_CONFIG_NAME) { + Err(x) => return x, + Ok(v) => v, + }; + + let pool_name = match settings::get_config_value(settings::CONFIG_POOL_NAME) { + Err(x) => return x, + Ok(v) => v, + }; + + let wallet_name = match settings::get_config_value(settings::CONFIG_WALLET_NAME) { + Err(x) => return x, + Ok(v) => v, + }; + + let wallet_type = match settings::get_config_value(settings::CONFIG_WALLET_TYPE) { + Err(x) => return x, + Ok(v) => v, + }; + match pool::create_pool_config(&pool_name, &config_name) { 0 => 0, x => return x, @@ -31,7 +51,7 @@ pub extern fn cxs_init (pool_name:*const c_char, x => return x, }; - return 0 + return error::SUCCESS.code_num } @@ -75,7 +95,7 @@ pub extern fn cxs_connection_create(recipient_info: *const c_char, connection_ha if connection_handle.is_null() {return error::UNKNOWN_ERROR.code_num} - let handle = build_connection("Whatever.".to_owned()); + let handle = build_connection(recipient_info.to_owned()); unsafe { *connection_handle = handle } @@ -158,19 +178,51 @@ pub extern fn cxs_proof_list_state(status_array: *mut CxsStatus) -> u32 { error: #[allow(unused_variables, unused_mut)] pub extern fn cxs_proof_get_state(proof_handle: u32, status: *mut c_char) -> u32 { error::SUCCESS.code_num } + + + #[cfg(test)] mod tests { + use super::*; - use utils::error::UNKNOWN_ERROR; + use std::path::Path; + use std::ffi::CString; + use std::ptr; + use std::error::Error; + use std::io::prelude::*; + use std::fs; + + #[test] + fn test_init_with_file() { + let config_path = "/tmp/test_init.json"; + let path = Path::new(config_path); + + let mut file = match fs::File::create(&path) { + Err(why) => panic!("couldn't create sample config file: {}", why.description()), + Ok(file) => file, + }; + + let content = "{ \"pool_name\" : \"my_pool\", \"config_name\":\"my_config\", \"wallet_name\":\"my_wallet\", \"wallet_type\":\"default\" }"; + match file.write_all(content.as_bytes()) { + Err(why) => panic!("couldn't write to sample config file: {}", why.description()), + Ok(_) => println!("sample config ready"), + } + + let result = cxs_init(CString::new(config_path).unwrap().into_raw()); + assert_eq!(result,0); + // Leave file around or other concurrent tests will fail + //fs::remove_file(config_path).unwrap(); + } + #[test] - fn test_init() { - let pool_name = CString::new("pool1").unwrap().into_raw(); - let config_name = CString::new("config1").unwrap().into_raw(); - let wallet_name = CString::new("wallet1").unwrap().into_raw(); - let wallet_type = CString::new("default").unwrap().into_raw(); + fn test_init_bad_path() { let empty_str = CString::new("").unwrap().into_raw(); - let result = cxs_init(pool_name, config_name, wallet_name, wallet_type); + assert_eq!(error::UNKNOWN_ERROR.code_num,cxs_init(empty_str)); + } + + #[test] + fn test_init_no_config_path() { + let result = cxs_init(ptr::null()); assert_eq!(result,0); - assert_eq!(UNKNOWN_ERROR.code_num,cxs_init(empty_str, config_name, wallet_name, wallet_type)); } } diff --git a/cxs/libcxs/src/lib.rs b/cxs/libcxs/src/lib.rs index b456ee4758..a60a1df991 100644 --- a/cxs/libcxs/src/lib.rs +++ b/cxs/libcxs/src/lib.rs @@ -1,7 +1,9 @@ +#![allow(dead_code)] extern crate indy; extern crate serde; extern crate serde_json; extern crate rand; +extern crate config; use std::path::Path; @@ -13,6 +15,7 @@ extern crate lazy_static; #[macro_use] mod utils; +mod settings; pub mod api; pub mod connection; diff --git a/cxs/libcxs/src/settings.rs b/cxs/libcxs/src/settings.rs new file mode 100644 index 0000000000..341628e6ef --- /dev/null +++ b/cxs/libcxs/src/settings.rs @@ -0,0 +1,130 @@ +extern crate config; + +use config::Config; +use std::sync::RwLock; +use utils::error; +use std::path::Path; + + +pub static CONFIG_POOL_NAME: &'static str = "pool_name"; +pub static CONFIG_POOL_CONFIG_NAME: &'static str = "config_name"; +pub static CONFIG_WALLET_NAME: &'static str = "wallet_name"; +pub static CONFIG_WALLET_TYPE: &'static str = "wallet_type"; +pub static CONFIG_AGENT_ENDPOINT: &'static str = "agent_endpoint"; + +lazy_static! { + static ref SETTINGS: RwLock = RwLock::new(Config::default()); +} + +pub fn set_defaults() -> u32 { + + let mut settings = match SETTINGS.write() { + Err(_) => return error::UNKNOWN_ERROR.code_num, + Ok(y) => y, + }; + + settings.set_default(CONFIG_POOL_NAME,"pool1"); + settings.set_default(CONFIG_POOL_CONFIG_NAME,"config1"); + settings.set_default(CONFIG_WALLET_NAME,"wallet1"); + settings.set_default(CONFIG_WALLET_TYPE,"default"); + settings.set_default(CONFIG_AGENT_ENDPOINT,"http://127.0.0.1:8080"); + + error::SUCCESS.code_num +} + +pub fn process_config_file(path: &str) -> u32 { + + if !Path::new(path).is_file() {return error::UNKNOWN_ERROR.code_num} + + match SETTINGS.write() { + Err(_) => return error::UNKNOWN_ERROR.code_num, + Ok(mut y) => y.merge(config::File::with_name(path)).unwrap(), + }; + + error::SUCCESS.code_num +} + +pub fn get_config_value(key: &str) -> Result { + + match SETTINGS.read() { + Err(_) => Err(error::UNKNOWN_ERROR.code_num), + Ok(y) => match y.get_str(key) { + Err(_) => Err(error::UNKNOWN_ERROR.code_num), + Ok(value) => Ok(value), + }, + } +} + + +#[cfg(test)] +pub mod tests { + use std::error::Error; + use std::io::prelude::*; + use std::fs; + use super::*; + + #[test] + fn test_invalid_config_value() { + match get_config_value("garbage") { + Err(x) => assert_eq!(x, error::UNKNOWN_ERROR.code_num), + Ok(v) => assert_eq!(v,"totalgarbage"), //if test gets here it will fail + }; + } + + #[test] + fn test_bad_path() { + //test bad path + let tmp_string = "garbage.txt"; + let rc = process_config_file(&tmp_string); + assert_eq!(rc, error::UNKNOWN_ERROR.code_num); + } + + #[test] + fn test_process_config_file() { + let a = "a"; + let b = "b"; + let c = "c"; + let d = "d"; + + let config_path = "/tmp/test_settings.json"; + let path = Path::new(config_path); + + let mut file = match fs::File::create(&path) { + Err(why) => panic!("couldn't create sample config file: {}", why.description()), + Ok(file) => file, + }; + + let content = "{ \"a\" : \"a\", \"b\":\"b\", \"c\":\"c\", \"d\":\"d\" }"; + + match file.write_all(content.as_bytes()) { + Err(why) => panic!("couldn't write to sample config file: {}", why.description()), + Ok(_) => println!("sample config ready"), + } + + let rc = process_config_file(&config_path); + assert_eq!(rc, error::SUCCESS.code_num); + + match get_config_value(&a) { + Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here + Ok(v) => assert_eq!(v,a), + }; + + match get_config_value(&b) { + Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here + Ok(v) => assert_eq!(v,b), + }; + + match get_config_value(&c) { + Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here + Ok(v) => assert_eq!(v,c), + }; + + match get_config_value(&d) { + Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here + Ok(v) => assert_eq!(v,d), + }; + + // Leave file around or other concurrent tests will fail + //fs::remove_file(config_path).unwrap(); + } +} diff --git a/cxs/wrappers/node/src/rustlib.js b/cxs/wrappers/node/src/rustlib.js index d4c00df247..4070bc4a24 100644 --- a/cxs/wrappers/node/src/rustlib.js +++ b/cxs/wrappers/node/src/rustlib.js @@ -1,5 +1,5 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FFIConfiguration = { - 'cxs_init': ['int', ['string', 'string', 'string', 'string']] + 'cxs_init': ['int', ['string']] }; diff --git a/cxs/wrappers/node/test/index-test.js b/cxs/wrappers/node/test/index-test.js index 56d15f1f58..9ecd4303a9 100644 --- a/cxs/wrappers/node/test/index-test.js +++ b/cxs/wrappers/node/test/index-test.js @@ -13,10 +13,10 @@ describe('call to cxs_init with provided path', function() { path += "/lib/libcxs.so"; var run = new CXSRuntime(new CXSRuntimeConfig(path)); it('should return 0', function () { - assert.equal(run.ffi.cxs_init('pool1', 'config1', 'wallet1','default'), 0); + assert.equal(run.ffi.cxs_init(null), 0); }) - it('should return 1002', function() { - assert.equal(run.ffi.cxs_init(' ', 'config1', 'wallet1','default'), 0); + it('should return 1001', function() { + assert.equal(run.ffi.cxs_init('garbage'), 1001); }) });