Added new option -l to write log messages to file. Changed old -l flag to -b.
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alfis"
|
name = "alfis"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
authors = ["Revertron <alfis@revertron.com>"]
|
authors = ["Revertron <alfis@revertron.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@@ -12,7 +12,7 @@ repository = "https://github.com/Revertron/Alfis"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
getopts = "0.2.21"
|
getopts = "0.2.21"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
simple_logger = "1.11.0"
|
simplelog = "0.10"
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
digest = "0.9.0"
|
digest = "0.9.0"
|
||||||
sha2 = "0.9.3"
|
sha2 = "0.9.3"
|
||||||
|
|||||||
@@ -31,4 +31,9 @@ pub const ZONE_MAX_LENGTH: usize = 10;
|
|||||||
pub const MAX_RECONNECTS: u32 = 5;
|
pub const MAX_RECONNECTS: u32 = 5;
|
||||||
|
|
||||||
pub const CLASS_ZONE: &str = "zone";
|
pub const CLASS_ZONE: &str = "zone";
|
||||||
pub const CLASS_DOMAIN: &str = "domain";
|
pub const CLASS_DOMAIN: &str = "domain";
|
||||||
|
|
||||||
|
/// Public nodes listen port
|
||||||
|
pub const LISTEN_PORT: u16 = 4244;
|
||||||
|
pub const UI_REFRESH_DELAY_MS: u128 = 250;
|
||||||
|
pub const LOG_REFRESH_DELAY_SEC: u64 = 60;
|
||||||
|
|||||||
+16
-6
@@ -1,14 +1,17 @@
|
|||||||
use std::num;
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
pub mod constants;
|
|
||||||
pub use constants::*;
|
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
use std::num;
|
||||||
|
|
||||||
|
use mio::Token;
|
||||||
|
use rand::Rng;
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
use thread_priority::*;
|
use thread_priority::*;
|
||||||
|
|
||||||
|
pub use constants::*;
|
||||||
|
|
||||||
use crate::dns::protocol::DnsRecord;
|
use crate::dns::protocol::DnsRecord;
|
||||||
|
|
||||||
|
pub mod constants;
|
||||||
|
|
||||||
/// Convert bytes array to HEX format
|
/// Convert bytes array to HEX format
|
||||||
pub fn to_hex(buf: &[u8]) -> String {
|
pub fn to_hex(buf: &[u8]) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
@@ -95,6 +98,13 @@ pub fn is_yggdrasil(addr: &IpAddr) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets new token from old token, mutating the last
|
||||||
|
pub fn next(current: &mut Token) -> Token {
|
||||||
|
let next = current.0;
|
||||||
|
current.0 += 1;
|
||||||
|
Token(next)
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if this record has IP from Yggdrasil network
|
/// Checks if this record has IP from Yggdrasil network
|
||||||
/// https://yggdrasil-network.github.io
|
/// https://yggdrasil-network.github.io
|
||||||
pub fn is_yggdrasil_record(record: &DnsRecord) -> bool {
|
pub fn is_yggdrasil_record(record: &DnsRecord) -> bool {
|
||||||
@@ -134,8 +144,8 @@ pub fn setup_miner_thread(cpu: u32) {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{check_domain, is_yggdrasil};
|
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
use crate::{check_domain, is_yggdrasil};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_domain() {
|
fn test_check_domain() {
|
||||||
|
|||||||
+55
-16
@@ -9,14 +9,17 @@ use std::sync::{Arc, Mutex};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use getopts::Options;
|
use getopts::{Options, Matches};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn, LevelFilter};
|
use log::{debug, error, info, trace, warn, LevelFilter};
|
||||||
use simple_logger::SimpleLogger;
|
use simplelog::*;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use winapi::um::wincon::{ATTACH_PARENT_PROCESS, AttachConsole, FreeConsole};
|
use winapi::um::wincon::{ATTACH_PARENT_PROCESS, AttachConsole, FreeConsole};
|
||||||
|
|
||||||
use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore, ZONE_DIFFICULTY};
|
use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore, ZONE_DIFFICULTY};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::io::{Seek, SeekFrom};
|
||||||
|
|
||||||
#[cfg(feature = "webgui")]
|
#[cfg(feature = "webgui")]
|
||||||
mod web_ui;
|
mod web_ui;
|
||||||
@@ -42,8 +45,9 @@ fn main() {
|
|||||||
opts.optflag("n", "nogui", "Run without graphic user interface (default for no gui builds)");
|
opts.optflag("n", "nogui", "Run without graphic user interface (default for no gui builds)");
|
||||||
opts.optflag("v", "verbose", "Show more debug messages");
|
opts.optflag("v", "verbose", "Show more debug messages");
|
||||||
opts.optflag("d", "debug", "Show trace messages, more than debug");
|
opts.optflag("d", "debug", "Show trace messages, more than debug");
|
||||||
opts.optflag("l", "list", "List blocks from DB and exit");
|
opts.optflag("b", "blocks", "List blocks from DB and exit");
|
||||||
opts.optflag("g", "generate", "Generate new config file. Generated config will be printed to console.");
|
opts.optflag("g", "generate", "Generate new config file. Generated config will be printed to console.");
|
||||||
|
opts.optopt("l", "log", "Write log to file", "FILE");
|
||||||
opts.optopt("c", "config", "Path to config file", "FILE");
|
opts.optopt("c", "config", "Path to config file", "FILE");
|
||||||
opts.optopt("w", "work-dir", "Path to working directory", "DIRECTORY");
|
opts.optopt("w", "work-dir", "Path to working directory", "DIRECTORY");
|
||||||
opts.optopt("u", "upgrade", "Path to config file that you want to upgrade. Upgraded config will be printed to console.", "FILE");
|
opts.optopt("u", "upgrade", "Path to config file that you want to upgrade. Upgraded config will be printed to console.", "FILE");
|
||||||
@@ -82,13 +86,6 @@ fn main() {
|
|||||||
#[cfg(not(feature = "webgui"))]
|
#[cfg(not(feature = "webgui"))]
|
||||||
let no_gui = true;
|
let no_gui = true;
|
||||||
|
|
||||||
let mut level = LevelFilter::Info;
|
|
||||||
if opt_matches.opt_present("v") {
|
|
||||||
level = LevelFilter::Debug;
|
|
||||||
}
|
|
||||||
if opt_matches.opt_present("d") {
|
|
||||||
level = LevelFilter::Trace;
|
|
||||||
}
|
|
||||||
let config_name = match opt_matches.opt_str("c") {
|
let config_name = match opt_matches.opt_str("c") {
|
||||||
None => { SETTINGS_FILENAME.to_owned() }
|
None => { SETTINGS_FILENAME.to_owned() }
|
||||||
Some(path) => { path }
|
Some(path) => { path }
|
||||||
@@ -97,18 +94,14 @@ fn main() {
|
|||||||
env::set_current_dir(Path::new(&path)).expect(&format!("Unable to change working directory to '{}'", &path));
|
env::set_current_dir(Path::new(&path)).expect(&format!("Unable to change working directory to '{}'", &path));
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleLogger::new()
|
setup_logger(&opt_matches);
|
||||||
.with_level(level)
|
|
||||||
.with_module_level("mio::poll", LevelFilter::Warn)
|
|
||||||
.init()
|
|
||||||
.unwrap();
|
|
||||||
info!(target: LOG_TARGET_MAIN, "Starting ALFIS {}", env!("CARGO_PKG_VERSION"));
|
info!(target: LOG_TARGET_MAIN, "Starting ALFIS {}", env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
let settings = Settings::load(&config_name).expect(&format!("Cannot load settings from {}!", &config_name));
|
let settings = Settings::load(&config_name).expect(&format!("Cannot load settings from {}!", &config_name));
|
||||||
info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
|
info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
|
||||||
let keystore = Keystore::from_file(&settings.key_file, "");
|
let keystore = Keystore::from_file(&settings.key_file, "");
|
||||||
let chain: Chain = Chain::new(&settings);
|
let chain: Chain = Chain::new(&settings);
|
||||||
if opt_matches.opt_present("l") {
|
if opt_matches.opt_present("b") {
|
||||||
for i in 1..(chain.height() + 1) {
|
for i in 1..(chain.height() + 1) {
|
||||||
if let Some(block) = chain.get_block(i) {
|
if let Some(block) = chain.get_block(i) {
|
||||||
info!(target: LOG_TARGET_MAIN, "{:?}", &block);
|
info!(target: LOG_TARGET_MAIN, "{:?}", &block);
|
||||||
@@ -152,12 +145,58 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets up logger in accordance with command line options
|
||||||
|
fn setup_logger(opt_matches: &Matches) {
|
||||||
|
let mut level = LevelFilter::Info;
|
||||||
|
if opt_matches.opt_present("v") {
|
||||||
|
level = LevelFilter::Debug;
|
||||||
|
}
|
||||||
|
if opt_matches.opt_present("d") {
|
||||||
|
level = LevelFilter::Trace;
|
||||||
|
}
|
||||||
|
let config = ConfigBuilder::new()
|
||||||
|
.add_filter_ignore_str("mio::poll")
|
||||||
|
.set_thread_level(LevelFilter::Off)
|
||||||
|
.set_location_level(LevelFilter::Off)
|
||||||
|
.set_target_level(LevelFilter::Error)
|
||||||
|
.set_time_level(LevelFilter::Error)
|
||||||
|
.set_time_to_local(true)
|
||||||
|
.build();
|
||||||
|
match opt_matches.opt_str("l") {
|
||||||
|
None => {
|
||||||
|
if let Err(e) = TermLogger::init(level, config, TerminalMode::Stdout, ColorChoice::Auto) {
|
||||||
|
println!("Unable to initialize logger!\n{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(path) => {
|
||||||
|
let file = match OpenOptions::new().write(true).create(true).open(&path) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
file.seek(SeekFrom::End(0)).unwrap();
|
||||||
|
file
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Could not open log file '{}' for writing!\n{}", &path, e);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CombinedLogger::init(
|
||||||
|
vec![
|
||||||
|
TermLogger::new(level, config.clone(), TerminalMode::Stdout, ColorChoice::Auto),
|
||||||
|
WriteLogger::new(level, config, file),
|
||||||
|
]
|
||||||
|
).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets own domains by current loaded keystore and writes them to log
|
||||||
fn print_my_domains(context: &Arc<Mutex<Context>>) {
|
fn print_my_domains(context: &Arc<Mutex<Context>>) {
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
let domains = context.chain.get_my_domains(&context.keystore);
|
let domains = context.chain.get_my_domains(&context.keystore);
|
||||||
debug!("Domains: {:?}", &domains);
|
debug!("Domains: {:?}", &domains);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates genesis (origin) block if `origin` is empty in config and we don't have any blocks in DB
|
||||||
fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Miner>>) {
|
fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Miner>>) {
|
||||||
// If there is no origin in settings and no blockchain in DB, generate genesis block
|
// If there is no origin in settings and no blockchain in DB, generate genesis block
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
|
|||||||
+16
-18
@@ -3,26 +3,25 @@ extern crate serde_json;
|
|||||||
|
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::net::{IpAddr, Shutdown, SocketAddr, SocketAddrV4};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
use mio::{Events, Interest, Poll, Registry, Token};
|
use mio::{Events, Interest, Poll, Registry, Token};
|
||||||
use mio::event::Event;
|
use mio::event::Event;
|
||||||
use mio::net::{TcpListener, TcpStream};
|
use mio::net::{TcpListener, TcpStream};
|
||||||
#[allow(unused_imports)]
|
|
||||||
use log::{trace, debug, info, warn, error};
|
|
||||||
|
|
||||||
use std::net::{SocketAddr, IpAddr, SocketAddrV4, Shutdown};
|
|
||||||
use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, is_yggdrasil};
|
|
||||||
use crate::blockchain::types::BlockQuality;
|
|
||||||
use crate::commons::CHAIN_VERSION;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
|
use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State};
|
||||||
|
use crate::blockchain::types::BlockQuality;
|
||||||
|
use crate::commons::*;
|
||||||
|
|
||||||
const SERVER: Token = Token(0);
|
const SERVER: Token = Token(0);
|
||||||
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(1000));
|
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(1000));
|
||||||
pub const LISTEN_PORT: u16 = 4244;
|
|
||||||
const MAX_PACKET_SIZE: usize = 1 * 1024 * 1024; // 1 Mb
|
const MAX_PACKET_SIZE: usize = 1 * 1024 * 1024; // 1 Mb
|
||||||
const MAX_READ_BLOCK_TIME: u128 = 500;
|
const MAX_READ_BLOCK_TIME: u128 = 500;
|
||||||
|
|
||||||
@@ -63,7 +62,8 @@ impl Network {
|
|||||||
// Starting peer connections to bootstrap nodes
|
// Starting peer connections to bootstrap nodes
|
||||||
peers.connect_peers(&peers_addrs, &poll.registry(), &mut unique_token, yggdrasil_only);
|
peers.connect_peers(&peers_addrs, &poll.registry(), &mut unique_token, yggdrasil_only);
|
||||||
|
|
||||||
let mut peers_timer = Instant::now();
|
let mut ui_timer = Instant::now();
|
||||||
|
let mut log_timer = Instant::now();
|
||||||
let mut bootstrap_timer = Instant::now();
|
let mut bootstrap_timer = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
if peers.get_peers_count() == 0 && bootstrap_timer.elapsed().as_secs() > 60 {
|
if peers.get_peers_count() == 0 && bootstrap_timer.elapsed().as_secs() > 60 {
|
||||||
@@ -138,7 +138,7 @@ impl Network {
|
|||||||
}
|
}
|
||||||
events.clear();
|
events.clear();
|
||||||
|
|
||||||
if peers_timer.elapsed().as_millis() > 250 {
|
if ui_timer.elapsed().as_millis() > UI_REFRESH_DELAY_MS {
|
||||||
// Send pings to idle peers
|
// Send pings to idle peers
|
||||||
let (height, hash) = {
|
let (height, hash) = {
|
||||||
let mut context = context.lock().unwrap();
|
let mut context = context.lock().unwrap();
|
||||||
@@ -147,11 +147,15 @@ impl Network {
|
|||||||
if nodes > 0 {
|
if nodes > 0 {
|
||||||
context.bus.post(crate::event::Event::NetworkStatus { nodes, blocks: height });
|
context.bus.post(crate::event::Event::NetworkStatus { nodes, blocks: height });
|
||||||
}
|
}
|
||||||
|
if log_timer.elapsed().as_secs() > LOG_REFRESH_DELAY_SEC {
|
||||||
|
info!("Active nodes count: {}, blocks count: {}", nodes, height);
|
||||||
|
log_timer = Instant::now();
|
||||||
|
}
|
||||||
(height, context.chain.last_hash())
|
(height, context.chain.last_hash())
|
||||||
};
|
};
|
||||||
peers.update(poll.registry(), height, hash);
|
peers.update(poll.registry(), height, hash);
|
||||||
peers.connect_new_peers(poll.registry(), &mut unique_token, yggdrasil_only);
|
peers.connect_new_peers(poll.registry(), &mut unique_token, yggdrasil_only);
|
||||||
peers_timer = Instant::now();
|
ui_timer = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !running.load(Ordering::SeqCst) {
|
if !running.load(Ordering::SeqCst) {
|
||||||
@@ -557,12 +561,6 @@ fn check_block(block: &Block, prev: &Block) -> bool {
|
|||||||
prev.index == block.index - 1 && prev.hash == block.prev_block_hash
|
prev.index == block.index - 1 && prev.hash == block.prev_block_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn next(current: &mut Token) -> Token {
|
|
||||||
let next = current.0;
|
|
||||||
current.0 += 1;
|
|
||||||
Token(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn would_block(err: &io::Error) -> bool {
|
fn would_block(err: &io::Error) -> bool {
|
||||||
err.kind() == io::ErrorKind::WouldBlock
|
err.kind() == io::ErrorKind::WouldBlock
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-11
@@ -1,17 +1,18 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::net::{SocketAddr, IpAddr, Shutdown, ToSocketAddrs};
|
use std::net::{IpAddr, Shutdown, SocketAddr, ToSocketAddrs};
|
||||||
use mio::{Token, Interest, Registry};
|
|
||||||
|
use chrono::Utc;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
use mio::{Interest, Registry, Token};
|
||||||
use mio::net::TcpStream;
|
use mio::net::TcpStream;
|
||||||
use crate::p2p::{Peer, State, Message};
|
|
||||||
use crate::p2p::network::LISTEN_PORT;
|
|
||||||
use crate::p2p::network::next;
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use rand::seq::IteratorRandom;
|
use rand::seq::IteratorRandom;
|
||||||
#[allow(unused_imports)]
|
|
||||||
use log::{trace, debug, info, warn, error};
|
use crate::{Bytes, commons};
|
||||||
use crate::{Bytes, is_yggdrasil, commons};
|
use crate::commons::*;
|
||||||
use crate::commons::MAX_RECONNECTS;
|
use crate::p2p::{Message, Peer, State};
|
||||||
use chrono::Utc;
|
use crate::commons::next;
|
||||||
|
|
||||||
pub struct Peers {
|
pub struct Peers {
|
||||||
peers: HashMap<Token, Peer>,
|
peers: HashMap<Token, Peer>,
|
||||||
@@ -90,7 +91,7 @@ impl Peers {
|
|||||||
peers.insert(peer.to_owned());
|
peers.insert(peer.to_owned());
|
||||||
peers
|
peers
|
||||||
});
|
});
|
||||||
debug!("Got {} peers", peers.len());
|
debug!("Got {} peers from exchange", peers.len());
|
||||||
//debug!("Got {} peers: {:?}", peers.len(), &peers);
|
//debug!("Got {} peers: {:?}", peers.len(), &peers);
|
||||||
// TODO make it return error if these peers are wrong and seem like an attack
|
// TODO make it return error if these peers are wrong and seem like an attack
|
||||||
for peer in peers.iter() {
|
for peer in peers.iter() {
|
||||||
|
|||||||
Reference in New Issue
Block a user