Addition of configuration file (#79)

* addition of configuration file to grin executable, instructions on how it's picked up are in grin.toml
* Starting to add a configuration file, and change some elements of configuration structures to make them more consistent
This commit is contained in:
Yeastplume 2017-07-13 17:30:33 +00:00 committed by Ignotus Peverell
parent e2ebd854e1
commit 1ede61d2a2
13 changed files with 531 additions and 77 deletions

View file

@ -4,11 +4,12 @@ version = "0.1.0"
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
[workspace]
members = ["api", "chain", "core", "grin", "p2p", "store", "util", "pool", "wallet"]
members = ["api", "chain", "config", "core", "grin", "p2p", "store", "util", "pool", "wallet"]
[dependencies]
grin_api = { path = "./api" }
grin_wallet = { path = "./wallet" }
grin_config = { path = "./config" }
secp256k1zkp = { path = "./secp256k1zkp" }
clap = "^2.23.3"

14
config/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "grin_config"
version = "0.1.0"
authors = [" yeastplume"]
workspace = ".."
[dependencies]
serde = "~1.0.8"
serde_derive = "~1.0.8"
toml = "0.4"
grin_grin = { path = "../grin" }
grin_p2p = { path = "../p2p" }
grin_wallet = { path = "../wallet"}

212
config/src/config.rs Normal file
View file

@ -0,0 +1,212 @@
// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Configuration file management
use std::env;
use std::io::Read;
use std::path::PathBuf;
use std::fs::File;
use toml;
use grin::{ServerConfig,
MinerConfig};
use wallet::WalletConfig;
use types::{ConfigMembers,
GlobalConfig,
ConfigError};
/// The default file name to use when trying to derive
/// the config file location
const CONFIG_FILE_NAME: &'static str = "grin.toml";
const GRIN_HOME: &'static str = ".grin";
/// Returns the defaults, as strewn throughout the code
impl Default for ConfigMembers {
fn default() -> ConfigMembers {
ConfigMembers {
server: ServerConfig::default(),
mining: Some(MinerConfig::default()),
//wallet: Some(WalletConfig::default()),
}
}
}
impl Default for GlobalConfig {
fn default() -> GlobalConfig{
GlobalConfig {
config_file_path: None,
using_config_file: false,
members: Some(ConfigMembers::default())
}
}
}
impl GlobalConfig {
/// Need to decide on rules where to read the config file from,
/// but will take a stab at logic for now
fn derive_config_location(&mut self) -> Result<(), ConfigError> {
//First, check working directory
let mut config_path = env::current_dir().unwrap();
config_path.push(CONFIG_FILE_NAME);
if config_path.exists() {
self.config_file_path = Some(config_path);
return Ok(())
}
//Next, look in directory of executable
let mut config_path=env::current_exe().unwrap();
config_path.pop();
config_path.push(CONFIG_FILE_NAME);
if config_path.exists() {
self.config_file_path = Some(config_path);
return Ok(())
}
//Then look in {user_home}/.grin
let config_path = env::home_dir();
if let Some(mut p) = config_path {
p.push(GRIN_HOME);
p.push(CONFIG_FILE_NAME);
if p.exists() {
self.config_file_path = Some(p);
return Ok(())
}
}
// Give up
Err(ConfigError::FileNotFoundError(String::from("")))
}
/// Takes the path to a config file, or if NONE, tries
/// to determine a config file based on rules in
/// derive_config_location
pub fn new(file_path:Option<&str>) -> Result<GlobalConfig, ConfigError> {
let mut return_value = GlobalConfig::default();
if let Some(fp) = file_path {
return_value.config_file_path = Some(PathBuf::from(&fp));
} else {
return_value.derive_config_location();
}
//No attempt at a config file, just return defaults
if let None = return_value.config_file_path {
return Ok(return_value);
}
//Config file path is given but not valid
if !return_value.config_file_path.as_mut().unwrap().exists() {
return Err(
ConfigError::FileNotFoundError(String::from(return_value.config_file_path.as_mut()
.unwrap().to_str().unwrap().clone()))
);
}
//Try to parse the config file if it exists
//explode if it does exist but something's wrong
//with it
return_value.read_config()
}
pub fn read_config(mut self) -> Result<GlobalConfig, ConfigError> {
let mut file = File::open(self.config_file_path.as_mut().unwrap())?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let decoded:Result<ConfigMembers, toml::de::Error> = toml::from_str(&contents);
match decoded {
Ok(mut gc) => {
//Put the struct back together, because the config
//file was flattened a bit
gc.server.mining_config = gc.mining.clone();
self.using_config_file = true;
self.members = Some(gc);
return Ok(self)
},
Err (e) => {
return Err(
ConfigError::ParseError(String::from(self.config_file_path.as_mut()
.unwrap().to_str().unwrap().clone()),
String::from(format!("{}", e))
)
);
}
}
}
pub fn ser_config(&mut self) -> Result<String, ConfigError> {
let encoded:Result<String, toml::ser::Error> = toml::to_string(self.members.as_mut().unwrap());
match encoded {
Ok(enc) => {
return Ok(enc)
},
Err (e) => {
return Err(
ConfigError::SerializationError(
String::from(format!("{}", e))
)
);
}
}
}
/*pub fn wallet_enabled(&mut self) -> bool {
return self.members.as_mut().unwrap().wallet.as_mut().unwrap().enable_wallet;
}*/
pub fn mining_enabled(&mut self) -> bool {
return self.members.as_mut().unwrap().mining.as_mut().unwrap().enable_mining;
}
}
#[test]
fn test_read_config() {
let toml_str = r#"
#Section is optional, if not here or enable_server is false, will only run wallet
[server]
enable_server = true
api_http_addr = "127.0.0.1"
db_root = "."
seeding_type = "None"
test_mode = false
#7 = FULL_NODE, not sure how to serialise this properly to use constants
capabilities = [7]
[server.p2p_config]
host = "127.0.0.1"
port = 13414
#Mining section is optional, if it's not here it will default to not mining
[mining]
enable_mining = true
wallet_receiver_url = "http://127.0.0.1:13415"
burn_reward = false
#testing value, optional
#slow_down_in_millis = 30
#testing value, should really be removed and read from consensus instead, optional
#cuckoo_size = 12
"#;
let mut decoded: GlobalConfig = toml::from_str(toml_str).unwrap();
decoded.server.as_mut().unwrap().mining_config = decoded.mining;
println!("Decoded.server: {:?}", decoded.server);
println!("Decoded wallet: {:?}", decoded.wallet);
panic!("panic");
}

36
config/src/lib.rs Normal file
View file

@ -0,0 +1,36 @@
// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Crate wrapping up the Grin binary and configuration file
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate grin_grin as grin;
extern crate grin_p2p as p2p;
extern crate grin_wallet as wallet;
pub mod config;
pub mod types;
pub use types::{GlobalConfig, ConfigMembers, ConfigError};

103
config/src/types.rs Normal file
View file

@ -0,0 +1,103 @@
// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Public types for config modules
use std::path::PathBuf;
use std::io;
use std::fmt;
use grin::{ServerConfig,
MinerConfig};
use wallet::WalletConfig;
/// Error type wrapping config errors.
#[derive(Debug)]
pub enum ConfigError {
/// Error with parsing of config file
ParseError (String, String),
/// Error with fileIO while reading config file
FileIOError (String, String),
/// No file found
FileNotFoundError (String),
/// Error serializing config values
SerializationError (String),
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConfigError::ParseError(ref file_name, ref message) => {
write!(f, "Error parsing configuration file at {} - {}",file_name, message)
}
ConfigError::FileIOError(ref file_name, ref message) => {
write!(f, "{} {}", message, file_name)
}
ConfigError::FileNotFoundError(ref file_name) => {
write!(f, "Configuration file not found: {}", file_name)
}
ConfigError::SerializationError(ref message) => {
write!(f, "Error serializing configuration: {}", message)
}
}
}
}
impl From<io::Error> for ConfigError {
fn from(error: io::Error) -> ConfigError {
ConfigError::FileIOError(
String::from(""),
String::from(format!("Error loading config file: {}",error)),
)
}
}
/// Going to hold all of the various configuration types
/// separately for now, then put them together as a single
/// ServerConfig object afterwards. This is to flatten
/// out the configuration file into logical sections,
/// as they tend to be quite nested in the code
/// Most structs optional, as they may or may not
/// be needed depending on what's being run
#[derive(Debug, Serialize, Deserialize)]
pub struct GlobalConfig {
//Keep track of the file we've read
pub config_file_path: Option<PathBuf>,
//keep track of whether we're using
//a config file or just the defaults
//for each member
pub using_config_file: bool,
pub members: Option<ConfigMembers>,
}
/// Keeping an 'inner' structure here, as the top
/// level GlobalConfigContainer options might want to keep
/// internal state that we don't necessarily
/// want serialised or deserialised
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfigMembers {
pub server: ServerConfig,
pub mining: Option<MinerConfig>,
//removing wallet from here for now,
//as its concerns are separate from the server's, really
//given it needs to manage keys. It should probably
//stay command line only for the time being
//pub wallet: Option<WalletConfig>
}

60
grin.toml Normal file
View file

@ -0,0 +1,60 @@
# Sample Server Configuration File for Grin
#
# When running the grin executable without specifying any command line
# arguments, it will look for this file in three places, in the following
# order:
#
# -The working directory
# -The directory in which the executable resides
# -[user home]/.grin
#
#Server connection details
[server]
#the address on which services will listen, e.g. Transaction Pool
api_http_addr = "127.0.0.1:13413"
#the directory, relative to current, in which the grin blockchain
#is stored
db_root = ".grin"
#How to seed this server, can be None, List or WebStatic
seeding_type = "None"
#if seeding_type = List, the list of peers to connect to.
#seeds = ["192.168.0.1:8080","192.168.0.2:8080"]
#Whether to run in test mode, which at the moment affects cuckoo_size
#if this is false tries to use a slow cuckoo30 at the moment, not
#recommended
test_mode = true
#7 = Bit flags for FULL_NODE, this structure needs to be changed
#internally to make it more configurable
capabilities = [7]
#The P2P server details (i.e. the server that communicates with other
#grin server nodes
[server.p2p_config]
host = "127.0.0.1"
port = 13414
#Mining details. This section is optional. If it's not here, the server
#will default to not mining.
[mining]
#flag whether mining is enabled
enable_mining = true
#the wallet reciever to which coinbase rewards will be sent
wallet_receiver_url = "http://127.0.0.1:13415"
#whether to ignore the reward (mostly for testing)
burn_reward = true
#testing value, optional
#slow_down_in_millis = 30
#testing value, should really be removed and read from consensus instead, optional
#cuckoo_size = 12

View file

@ -95,14 +95,15 @@ impl Miner {
let mut sol = None;
debug!("(Server ID: {}) Mining at Cuckoo{} for at most 2 secs on block {} at difficulty {}.",
self.debug_output_id,
self.config.cuckoo_size,
self.config.cuckoo_size.unwrap(),
latest_hash,
b.header.difficulty);
let mut iter_count = 0;
if self.config.slow_down_in_millis > 0 {
if self.config.slow_down_in_millis != None && self.config.slow_down_in_millis.unwrap() > 0 {
debug!("(Server ID: {}) Artificially slowing down loop by {}ms per iteration.",
self.debug_output_id,
self.config.slow_down_in_millis);
self.config.slow_down_in_millis.unwrap());
}
while head.hash() == latest_hash && time::get_time().sec < deadline {
let pow_hash = b.hash();
@ -123,8 +124,8 @@ impl Miner {
iter_count += 1;
//Artificial slow down
if self.config.slow_down_in_millis > 0 {
thread::sleep(std::time::Duration::from_millis(self.config.slow_down_in_millis));
if self.config.slow_down_in_millis != None && self.config.slow_down_in_millis.unwrap() > 0 {
thread::sleep(std::time::Duration::from_millis(self.config.slow_down_in_millis.unwrap()));
}
}
@ -133,7 +134,7 @@ impl Miner {
info!("(Server ID: {}) Found valid proof of work, adding block {}.",
self.debug_output_id, b.hash());
b.header.pow = proof;
let opts = if self.config.cuckoo_size < consensus::DEFAULT_SIZESHIFT as u32 {
let opts = if self.config.cuckoo_size.unwrap() < consensus::DEFAULT_SIZESHIFT as u32 {
chain::EASY_POW
} else {
chain::NONE

View file

@ -62,10 +62,10 @@ impl Server {
check_config(&mut config);
let mut evtlp = reactor::Core::new().unwrap();
let mining_config = config.mining_config.clone();
let mut mining_config = config.mining_config.clone();
let serv = Server::future(config, &evtlp.handle())?;
if mining_config.enable_mining {
serv.start_miner(mining_config);
if mining_config.as_mut().unwrap().enable_mining {
serv.start_miner(mining_config.unwrap());
}
let forever = Timer::default()
@ -99,14 +99,14 @@ impl Server {
tx_pool.clone(),
peer_store.clone()));
let p2p_server =
Arc::new(p2p::Server::new(config.capabilities, config.p2p_config, net_adapter.clone()));
Arc::new(p2p::Server::new(config.capabilities, config.p2p_config.unwrap(), net_adapter.clone()));
chain_adapter.init(p2p_server.clone());
let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), p2p_server.clone());
match config.seeding_type.clone() {
Seeding::None => {}
Seeding::List(seeds) => {
seed.connect_and_monitor(evt_handle.clone(), seed::predefined_seeds(seeds));
Seeding::List => {
seed.connect_and_monitor(evt_handle.clone(), seed::predefined_seeds(config.seeds.as_mut().unwrap().clone()));
}
Seeding::WebStatic => {
seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
@ -150,9 +150,9 @@ impl Server {
#[cfg(not(feature = "use-cuckoo-miner"))]
pub fn start_miner(&self, config: MinerConfig) {
let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
miner.set_debug_output_id(format!("Port {}",self.config.p2p_config.port));
miner.set_debug_output_id(format!("Port {}",self.config.p2p_config.unwrap().port));
thread::spawn(move || {
let test_cuckoo_miner = cuckoo::Miner::new(consensus::EASINESS, config.cuckoo_size.clone());
let test_cuckoo_miner = cuckoo::Miner::new(consensus::EASINESS, config.cuckoo_size.unwrap().clone());
miner.run_loop(test_cuckoo_miner);
});
}
@ -163,7 +163,7 @@ impl Server {
let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
miner.set_debug_output_id(format!("Port {}",self.config.p2p_config.port));
thread::spawn(move || {
let test_cuckoo_miner = PluginMiner::new(consensus::EASINESS, config.cuckoo_size.clone());
let test_cuckoo_miner = PluginMiner::new(consensus::EASINESS, config.cuckoo_size.unwrap().clone());
miner.run_loop(test_cuckoo_miner);
});
}
@ -186,9 +186,9 @@ impl Server {
fn check_config(config: &mut ServerConfig) {
// applying test/normal config
config.mining_config.cuckoo_size = if config.test_mode {
consensus::TEST_SIZESHIFT as u32
config.mining_config.as_mut().unwrap().cuckoo_size = if config.test_mode {
Some(consensus::TEST_SIZESHIFT as u32)
} else {
consensus::DEFAULT_SIZESHIFT as u32
Some(consensus::DEFAULT_SIZESHIFT as u32)
};
}

View file

@ -62,7 +62,7 @@ pub enum Seeding {
/// No seeding, mostly for tests that programmatically connect
None,
/// A list of seed addresses provided to the server
List(Vec<String>),
List,
/// Automatically download a text file with a list of server addresses
WebStatic,
}
@ -77,21 +77,24 @@ pub struct ServerConfig {
/// Network address for the Rest API HTTP server.
pub api_http_addr: String,
/// Setup the server for tests and testnet
pub test_mode: bool,
/// Method used to get the list of seed nodes for initial bootstrap.
pub seeding_type: Seeding,
/// The list of seed nodes, if using Seeding as a seed type
pub seeds: Option<Vec<String>>,
/// Capabilities expose by this node, also conditions which other peers this
/// node will have an affinity toward when connection.
pub capabilities: p2p::Capabilities,
/// Method used to get the list of seed nodes for initial bootstrap.
pub seeding_type: Seeding,
/// Configuration for the peer-to-peer server
pub p2p_config: p2p::P2PConfig,
pub p2p_config: Option<p2p::P2PConfig>,
/// Configuration for the mining daemon
pub mining_config: MinerConfig,
/// Setup the server for tests and testnet
pub test_mode: bool,
pub mining_config: Option<MinerConfig>,
}
/// Mining configuration
@ -109,10 +112,10 @@ pub struct MinerConfig {
/// a testing attribute for the time being that artifically slows down the
/// mining loop by adding a sleep to the thread
pub slow_down_in_millis: u64,
pub slow_down_in_millis: Option<u64>,
/// Size of Cuckoo Cycle to mine on
pub cuckoo_size: u32,
pub cuckoo_size: Option<u32>,
}
@ -124,8 +127,9 @@ impl Default for ServerConfig {
api_http_addr: "127.0.0.1:13415".to_string(),
capabilities: p2p::FULL_NODE,
seeding_type: Seeding::None,
p2p_config: p2p::P2PConfig::default(),
mining_config: MinerConfig::default(),
seeds: None,
p2p_config: Some(p2p::P2PConfig::default()),
mining_config: Some(MinerConfig::default()),
test_mode: true,
}
}
@ -137,8 +141,8 @@ impl Default for MinerConfig {
enable_mining: false,
wallet_receiver_url: "http://localhost:13416".to_string(),
burn_reward: false,
slow_down_in_millis: 0,
cuckoo_size: 0
slow_down_in_millis: Some(0),
cuckoo_size: Some(0)
}
}
}

View file

@ -203,9 +203,11 @@ impl LocalServerContainer {
let api_addr = format!("{}:{}", self.config.base_addr, self.config.api_server_port);
let mut seeding_type=grin::Seeding::None;
let mut seeds=Vec::new();
if self.config.seed_addr.len()>0{
seeding_type=grin::Seeding::List(vec![self.config.seed_addr.to_string()]);
seeding_type=grin::Seeding::List;
seeds=vec![self.config.seed_addr.to_string()];
}
@ -213,7 +215,8 @@ impl LocalServerContainer {
grin::ServerConfig{
api_http_addr: api_addr,
db_root: format!("{}/.grin", self.working_dir),
p2p_config: p2p::P2PConfig{port: self.config.p2p_server_port, ..p2p::P2PConfig::default()},
p2p_config: Some(p2p::P2PConfig{port: self.config.p2p_server_port, ..p2p::P2PConfig::default()}),
seeds: Some(seeds),
seeding_type: seeding_type,
..Default::default()
}, &event_loop.handle()).unwrap();
@ -229,9 +232,9 @@ impl LocalServerContainer {
let mut miner_config = grin::MinerConfig {
enable_mining: self.config.start_miner,
burn_reward: self.config.burn_mining_rewards,
cuckoo_size: self.config.cuckoo_size,
cuckoo_size: Some(self.config.cuckoo_size),
wallet_receiver_url : self.config.coinbase_wallet_address.clone(),
slow_down_in_millis: self.config.miner_slowdown_in_millis.clone(),
slow_down_in_millis: Some(self.config.miner_slowdown_in_millis.clone()),
..Default::default()
};

View file

@ -199,7 +199,7 @@ fn simulate_block_propagation() {
let miner_config = grin::MinerConfig{
enable_mining: true,
burn_reward: true,
cuckoo_size: consensus::TEST_SIZESHIFT as u32,
cuckoo_size: Some(consensus::TEST_SIZESHIFT as u32),
..Default::default()
};
@ -210,7 +210,7 @@ fn simulate_block_propagation() {
grin::ServerConfig{
api_http_addr: format!("127.0.0.1:{}", 20000+n),
db_root: format!("target/{}/grin-prop-{}", test_name_dir, n),
p2p_config: p2p::P2PConfig{port: 10000+n, ..p2p::P2PConfig::default()},
p2p_config: Some(p2p::P2PConfig{port: 10000+n, ..p2p::P2PConfig::default()}),
..Default::default()
}, &handle).unwrap();
servers.push(s);
@ -256,7 +256,7 @@ fn simulate_full_sync() {
let miner_config = grin::MinerConfig{
enable_mining: true,
burn_reward: true,
cuckoo_size: consensus::TEST_SIZESHIFT as u32,
cuckoo_size: Some(consensus::TEST_SIZESHIFT as u32),
..Default::default()
};
@ -266,7 +266,7 @@ fn simulate_full_sync() {
let s = grin::Server::future(
grin::ServerConfig{
db_root: format!("target/{}/grin-sync-{}", test_name_dir, n),
p2p_config: p2p::P2PConfig{port: 11000+n, ..p2p::P2PConfig::default()},
p2p_config: Some(p2p::P2PConfig{port: 11000+n, ..p2p::P2PConfig::default()}),
..Default::default()
}, &handle).unwrap();
servers.push(s);

View file

@ -26,10 +26,9 @@ extern crate tiny_keccak;
extern crate grin_api as api;
extern crate grin_grin as grin;
extern crate grin_wallet as wallet;
extern crate grin_config as config;
extern crate secp256k1zkp as secp;
const GRIN_HOME: &'static str = ".grin";
use std::env;
use std::thread;
use std::io::Read;
@ -44,6 +43,16 @@ use secp::Secp256k1;
use wallet::WalletConfig;
use config::{GlobalConfig, ConfigError};
fn start_from_config_file(mut global_config:GlobalConfig){
info!("Starting the Grin server from configuration file at {}", global_config.config_file_path.unwrap().to_str().unwrap());
grin::Server::start(global_config.members.as_mut().unwrap().server.clone()).unwrap();
loop {
thread::sleep(Duration::from_secs(60));
}
}
fn main() {
env_logger::init().unwrap();
@ -80,12 +89,6 @@ fn main() {
.long("wallet_url")
.help("A listening wallet receiver to which mining rewards will be sent")
.takes_value(true))
.arg(Arg::with_name("config")
.short("c")
.long("config")
.value_name("FILE.json")
.help("Sets a custom json configuration file")
.takes_value(true))
.subcommand(SubCommand::with_name("start")
.about("Start the Grin server as a daemon"))
.subcommand(SubCommand::with_name("stop")
@ -162,7 +165,34 @@ fn main() {
wallet_command(wallet_args);
}
_ => println!("Unknown command, use 'grin help' for a list of all commands"),
//If nothing is specified, try to load up and use a config file instead
//this should possibly become the way to configure most things
//with most command line options being phased out
_ => {
//This will return a global config object,
//which will either contain defaults for all
//of the config structures or a configuration
//read from a config file
let mut global_config = GlobalConfig::new(None);
match global_config {
Ok(gc) => {
if (gc.using_config_file){
start_from_config_file(gc);
} else {
//won't attempt to just start with defaults,
//and will reject
println!("Unknown command, and no configuration file was found.");
println!("Use 'grin help' for a list of all commands.");
}
}
Err(e) => {
println!("{}", e);
}
}
}
}
}
@ -173,10 +203,11 @@ fn main() {
fn server_command(server_args: &ArgMatches) {
info!("Starting the Grin server...");
// configuration wrangling
let mut server_config = read_config();
// just get defaults from the global config
let mut server_config = GlobalConfig::default().members.unwrap().server;
if let Some(port) = server_args.value_of("port") {
server_config.p2p_config.port = port.parse().unwrap();
server_config.p2p_config.as_mut().unwrap().port = port.parse().unwrap();
}
if let Some(api_port) = server_args.value_of("api_port") {
@ -185,17 +216,22 @@ fn server_command(server_args: &ArgMatches) {
}
if server_args.is_present("mine") {
server_config.mining_config.enable_mining = true;
server_config.mining_config.as_mut().unwrap().enable_mining = true;
}
if let Some(wallet_url) = server_args.value_of("wallet_url") {
server_config.mining_config.wallet_receiver_url = wallet_url.to_string();
server_config.mining_config.as_mut().unwrap().wallet_receiver_url = wallet_url.to_string();
}
if let Some(seeds) = server_args.values_of("seed") {
server_config.seeding_type = grin::Seeding::List(seeds.map(|s| s.to_string()).collect());
server_config.seeding_type = grin::Seeding::List;
server_config.seeds = Some(seeds.map(|s| s.to_string()).collect());
}
/*let mut sc = GlobalConfig::default();
sc.members.as_mut().unwrap().server = server_config.clone();
println!("{}", sc.ser_config().unwrap());*/
// start the server in the different run modes (interactive or daemon)
match server_args.subcommand() {
("run", _) => {
@ -291,22 +327,3 @@ fn wallet_command(wallet_args: &ArgMatches) {
}
}
fn read_config() -> grin::ServerConfig {
let mut config_path = env::home_dir().ok_or("Failed to detect home directory!").unwrap();
config_path.push(GRIN_HOME);
if !config_path.exists() {
return default_config();
}
let mut config_file = File::open(config_path).unwrap();
let mut config_content = String::new();
config_file.read_to_string(&mut config_content).unwrap();
serde_json::from_str(config_content.as_str()).unwrap()
}
fn default_config() -> grin::ServerConfig {
grin::ServerConfig {
test_mode: true,
seeding_type: grin::Seeding::WebStatic,
..Default::default()
}
}

View file

@ -76,8 +76,10 @@ impl From<api::Error> for Error {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WalletConfig {
//Whether to run a wallet
pub enable_wallet: bool,
//The api address that this api server (i.e. this wallet) will run
pub api_http_addr: String,
//The api address of a running server node, against which transaction inputs will be checked
@ -90,6 +92,7 @@ pub struct WalletConfig {
impl Default for WalletConfig {
fn default() -> WalletConfig {
WalletConfig {
enable_wallet: false,
api_http_addr: "http://127.0.0.1:13415".to_string(),
check_node_api_http_addr: "http://127.0.0.1:13415".to_string(),
data_file_dir: ".".to_string(),