Backports to 2.0.1-beta (#9145)
* parity-version: bump beta to 2.0.1 * ci: update version strings for snaps * Be more graceful on Aura difficulty validation (#9164) * Be more graceful on Aura difficulty validation * test: rejects_step_backwards * test: proposer_switching * test: rejects_future_block * test: reports_skipped * test: verify_empty_seal_steps * Remove node-health (#9119) * Remove node-health * Remove ntp_servers * Add --ntp-servers as legacy instead of removing it * Add --ntp-servers to deprecated args * Remove unused stuff * Remove _legacy_ntp_servers * parity: fix UserDefaults json parser (#9189) * parity: fix UserDefaults json parser * parity: use serde_derive for UserDefaults * parity: support deserialization of old UserDefault json format * parity: make UserDefaults serde backwards compatible * parity: tabify indentation in UserDefaults * Fix bugfix hard fork logic (#9138) * Fix bugfix hard fork logic * Remove dustProtectionTransition from bugfix category EIP-168 is not enabled by default * Remove unnecessary 'static * Disable per-sender limit for local transactions. (#9148) * Disable per-sender limit for local transactions. * Add a missing new line. * rpc: fix is_major_importing sync state condition (#9112) * rpc: fix is_major_importing sync state condition * rpc: fix informant printout when waiting for peers * fix verification in ethcore-sync collect_blocks (#9135) * docker: update hub dockerfile (#9173) * update Dockerfile for hub update to Ubuntu Xenial 16.04 fix cmake version * docker: fix tab indentation in hub dockerfile * rpc: fix broken merge * rcp: remove node_health leftover from merge * rpc: remove dapps leftover from merge
This commit is contained in:
@@ -794,10 +794,6 @@ usage! {
|
||||
"--no-config",
|
||||
"Don't load a configuration file.",
|
||||
|
||||
ARG arg_ntp_servers: (String) = "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123", or |c: &Config| c.misc.as_ref()?.ntp_servers.clone().map(|vec| vec.join(",")),
|
||||
"--ntp-servers=[HOSTS]",
|
||||
"Comma separated list of NTP servers to provide current time (host:port). Used to verify node health. Parity uses pool.ntp.org NTP servers; consider joining the pool: http://www.pool.ntp.org/join.html",
|
||||
|
||||
ARG arg_logging: (Option<String>) = None, or |c: &Config| c.misc.as_ref()?.logging.clone(),
|
||||
"-l, --logging=[LOGGING]",
|
||||
"Specify the logging level. Must conform to the same format as RUST_LOG.",
|
||||
@@ -1077,6 +1073,10 @@ usage! {
|
||||
ARG arg_dapps_path: (Option<String>) = None, or |c: &Config| c.dapps.as_ref()?._legacy_path.clone(),
|
||||
"--dapps-path=[PATH]",
|
||||
"Specify directory where dapps should be installed.",
|
||||
|
||||
ARG arg_ntp_servers: (Option<String>) = None, or |_| None,
|
||||
"--ntp-servers=[HOSTS]",
|
||||
"Does nothing; checking if clock is sync with NTP servers is now done on the UI.",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1350,7 +1350,6 @@ struct Snapshots {
|
||||
#[derive(Default, Debug, PartialEq, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Misc {
|
||||
ntp_servers: Option<Vec<String>>,
|
||||
logging: Option<String>,
|
||||
log_file: Option<String>,
|
||||
color: Option<bool>,
|
||||
@@ -1818,7 +1817,7 @@ mod tests {
|
||||
flag_can_restart: false,
|
||||
|
||||
// -- Miscellaneous Options
|
||||
arg_ntp_servers: "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123".into(),
|
||||
arg_ntp_servers: None,
|
||||
flag_version: false,
|
||||
arg_logging: Some("own_tx=trace".into()),
|
||||
arg_log_file: Some("/var/log/parity.log".into()),
|
||||
@@ -2024,7 +2023,6 @@ mod tests {
|
||||
disable_periodic: Some(true),
|
||||
}),
|
||||
misc: Some(Misc {
|
||||
ntp_servers: Some(vec!["0.parity.pool.ntp.org:123".into()]),
|
||||
logging: Some("own_tx=trace".into()),
|
||||
log_file: Some("/var/log/parity.log".into()),
|
||||
color: Some(true),
|
||||
|
||||
@@ -75,7 +75,6 @@ scale_verifiers = false
|
||||
disable_periodic = true
|
||||
|
||||
[misc]
|
||||
ntp_servers = ["0.parity.pool.ntp.org:123"]
|
||||
logging = "own_tx=trace"
|
||||
log_file = "/var/log/parity.log"
|
||||
color = true
|
||||
|
||||
@@ -348,7 +348,6 @@ impl Configuration {
|
||||
miner_options: self.miner_options()?,
|
||||
gas_price_percentile: self.args.arg_gas_price_percentile,
|
||||
poll_lifetime: self.args.arg_poll_lifetime,
|
||||
ntp_servers: self.ntp_servers(),
|
||||
ws_conf: ws_conf,
|
||||
http_conf: http_conf,
|
||||
ipc_conf: ipc_conf,
|
||||
@@ -574,10 +573,6 @@ impl Configuration {
|
||||
})
|
||||
}
|
||||
|
||||
fn ntp_servers(&self) -> Vec<String> {
|
||||
self.args.arg_ntp_servers.split(",").map(str::to_owned).collect()
|
||||
}
|
||||
|
||||
fn secretstore_config(&self) -> Result<SecretStoreConfiguration, String> {
|
||||
Ok(SecretStoreConfiguration {
|
||||
enabled: self.secretstore_enabled(),
|
||||
@@ -1368,12 +1363,6 @@ mod tests {
|
||||
miner_options: Default::default(),
|
||||
gas_price_percentile: 50,
|
||||
poll_lifetime: 60,
|
||||
ntp_servers: vec![
|
||||
"0.parity.pool.ntp.org:123".into(),
|
||||
"1.parity.pool.ntp.org:123".into(),
|
||||
"2.parity.pool.ntp.org:123".into(),
|
||||
"3.parity.pool.ntp.org:123".into(),
|
||||
],
|
||||
ws_conf: Default::default(),
|
||||
http_conf: Default::default(),
|
||||
ipc_conf: Default::default(),
|
||||
|
||||
@@ -225,6 +225,10 @@ pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
|
||||
result.push(Deprecated::Removed("--dapps-path"));
|
||||
}
|
||||
|
||||
if args.arg_ntp_servers.is_some() {
|
||||
result.push(Deprecated::Removed("--ntp-servers"));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -256,6 +260,7 @@ mod tests {
|
||||
args.arg_dapps_pass = Some(Default::default());
|
||||
args.flag_dapps_apis_all = true;
|
||||
args.flag_fast_and_loose = true;
|
||||
args.arg_ntp_servers = Some(Default::default());
|
||||
args
|
||||
}), vec![
|
||||
Deprecated::DoesNothing("--warp"),
|
||||
@@ -276,6 +281,7 @@ mod tests {
|
||||
Deprecated::Removed("--dapps-pass"),
|
||||
Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis"),
|
||||
Deprecated::Removed("--fast-and-loose"),
|
||||
Deprecated::Removed("--ntp-servers"),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ use io::{TimerToken, IoContext, IoHandler};
|
||||
use light::Cache as LightDataCache;
|
||||
use light::client::{LightChainClient, LightChainNotify};
|
||||
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
||||
use parity_rpc::{is_major_importing};
|
||||
use parity_rpc::is_major_importing_or_waiting;
|
||||
use parity_rpc::informant::RpcStats;
|
||||
use ethereum_types::H256;
|
||||
use bytes::Bytes;
|
||||
@@ -128,7 +128,7 @@ impl InformantData for FullNodeInformantData {
|
||||
|
||||
fn is_major_importing(&self) -> bool {
|
||||
let state = self.sync.as_ref().map(|sync| sync.status().state);
|
||||
is_major_importing(state, self.client.queue_info())
|
||||
is_major_importing_or_waiting(state, self.client.queue_info(), false)
|
||||
}
|
||||
|
||||
fn report(&self) -> Report {
|
||||
@@ -142,7 +142,8 @@ impl InformantData for FullNodeInformantData {
|
||||
cache_sizes.insert("queue", queue_info.mem_used);
|
||||
cache_sizes.insert("chain", blockchain_cache_info.total());
|
||||
|
||||
let (importing, sync_info) = match (self.sync.as_ref(), self.net.as_ref()) {
|
||||
let importing = self.is_major_importing();
|
||||
let sync_info = match (self.sync.as_ref(), self.net.as_ref()) {
|
||||
(Some(sync), Some(net)) => {
|
||||
let status = sync.status();
|
||||
let num_peers_range = net.num_peers_range();
|
||||
@@ -150,16 +151,15 @@ impl InformantData for FullNodeInformantData {
|
||||
|
||||
cache_sizes.insert("sync", status.mem_used);
|
||||
|
||||
let importing = is_major_importing(Some(status.state), queue_info.clone());
|
||||
(importing, Some(SyncInfo {
|
||||
Some(SyncInfo {
|
||||
last_imported_block_number: status.last_imported_block_number.unwrap_or(chain_info.best_block_number),
|
||||
last_imported_old_block_number: status.last_imported_old_block_number,
|
||||
num_peers: status.num_peers,
|
||||
max_peers: status.current_max_peers(num_peers_range.start, num_peers_range.end - 1),
|
||||
snapshot_sync: status.is_snapshot_syncing(),
|
||||
}))
|
||||
})
|
||||
}
|
||||
_ => (is_major_importing(self.sync.as_ref().map(|s| s.status().state), queue_info.clone()), None),
|
||||
_ => None
|
||||
};
|
||||
|
||||
Report {
|
||||
|
||||
@@ -57,7 +57,6 @@ extern crate ethcore_transaction as transaction;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethkey;
|
||||
extern crate kvdb;
|
||||
extern crate node_health;
|
||||
extern crate panic_hook;
|
||||
extern crate parity_hash_fetch as hash_fetch;
|
||||
extern crate parity_ipfs_api;
|
||||
|
||||
@@ -334,7 +334,7 @@ pub fn fatdb_switch_to_bool(switch: Switch, user_defaults: &UserDefaults, _algor
|
||||
}
|
||||
|
||||
pub fn mode_switch_to_bool(switch: Option<Mode>, user_defaults: &UserDefaults) -> Result<Mode, String> {
|
||||
Ok(switch.unwrap_or(user_defaults.mode.clone()))
|
||||
Ok(switch.unwrap_or(user_defaults.mode().clone()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -34,7 +34,6 @@ use jsonrpc_core::{self as core, MetaIoHandler};
|
||||
use light::client::LightChainClient;
|
||||
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache};
|
||||
use miner::external::ExternalMiner;
|
||||
use node_health::NodeHealth;
|
||||
use parity_reactor;
|
||||
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
|
||||
use parity_rpc::informant::{ActivityNotifier, ClientNotifier};
|
||||
@@ -224,7 +223,6 @@ pub struct FullDependencies {
|
||||
pub settings: Arc<NetworkSettings>,
|
||||
pub net_service: Arc<ManageNetwork>,
|
||||
pub updater: Arc<Updater>,
|
||||
pub health: NodeHealth,
|
||||
pub geth_compatibility: bool,
|
||||
pub ws_address: Option<Host>,
|
||||
pub fetch: FetchClient,
|
||||
@@ -329,7 +327,6 @@ impl FullDependencies {
|
||||
self.sync.clone(),
|
||||
self.updater.clone(),
|
||||
self.net_service.clone(),
|
||||
self.health.clone(),
|
||||
self.secret_store.clone(),
|
||||
self.logger.clone(),
|
||||
self.settings.clone(),
|
||||
@@ -430,7 +427,6 @@ pub struct LightDependencies<T> {
|
||||
pub secret_store: Arc<AccountProvider>,
|
||||
pub logger: Arc<RotatingLogger>,
|
||||
pub settings: Arc<NetworkSettings>,
|
||||
pub health: NodeHealth,
|
||||
pub on_demand: Arc<::light::on_demand::OnDemand>,
|
||||
pub cache: Arc<Mutex<LightDataCache>>,
|
||||
pub transaction_queue: Arc<RwLock<LightTransactionQueue>>,
|
||||
@@ -544,7 +540,6 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
|
||||
self.secret_store.clone(),
|
||||
self.logger.clone(),
|
||||
self.settings.clone(),
|
||||
self.health.clone(),
|
||||
signer,
|
||||
self.ws_address.clone(),
|
||||
self.gas_price_percentile,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::thread;
|
||||
@@ -42,7 +41,6 @@ use journaldb::Algorithm;
|
||||
use light::Cache as LightDataCache;
|
||||
use miner::external::ExternalMiner;
|
||||
use node_filter::NodeFilter;
|
||||
use node_health;
|
||||
use parity_reactor::EventLoop;
|
||||
use parity_rpc::{Origin, Metadata, NetworkSettings, informant, is_major_importing};
|
||||
use updater::{UpdatePolicy, Updater};
|
||||
@@ -95,7 +93,6 @@ pub struct RunCmd {
|
||||
pub miner_options: MinerOptions,
|
||||
pub gas_price_percentile: usize,
|
||||
pub poll_lifetime: u32,
|
||||
pub ntp_servers: Vec<String>,
|
||||
pub ws_conf: rpc::WsConfiguration,
|
||||
pub http_conf: rpc::HttpConfiguration,
|
||||
pub ipc_conf: rpc::IpcConfiguration,
|
||||
@@ -287,28 +284,6 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
|
||||
|
||||
// the dapps server
|
||||
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config));
|
||||
let node_health = {
|
||||
struct LightSyncStatus(Arc<LightSync>);
|
||||
impl fmt::Debug for LightSyncStatus {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "Light Sync Status")
|
||||
}
|
||||
}
|
||||
impl node_health::SyncStatus for LightSyncStatus {
|
||||
fn is_major_importing(&self) -> bool { self.0.is_major_importing() }
|
||||
fn peers(&self) -> (usize, usize) {
|
||||
let peers = sync::LightSyncProvider::peer_numbers(&*self.0);
|
||||
(peers.connected, peers.max)
|
||||
}
|
||||
}
|
||||
|
||||
let sync_status = Arc::new(LightSyncStatus(light_sync.clone()));
|
||||
node_health::NodeHealth::new(
|
||||
sync_status.clone(),
|
||||
node_health::TimeChecker::new(&cmd.ntp_servers, cpu_pool.clone()),
|
||||
event_loop.remote(),
|
||||
)
|
||||
};
|
||||
|
||||
// start RPCs
|
||||
let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies {
|
||||
@@ -316,7 +291,6 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
|
||||
client: client.clone(),
|
||||
sync: light_sync.clone(),
|
||||
net: light_sync.clone(),
|
||||
health: node_health,
|
||||
secret_store: account_provider,
|
||||
logger: logger,
|
||||
settings: Arc::new(cmd.net_settings),
|
||||
@@ -718,40 +692,11 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
let secret_store = account_provider.clone();
|
||||
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config));
|
||||
|
||||
// the dapps server
|
||||
let node_health = {
|
||||
let (sync, client) = (sync_provider.clone(), client.clone());
|
||||
|
||||
struct SyncStatus(Arc<sync::SyncProvider>, Arc<Client>, sync::NetworkConfiguration);
|
||||
impl fmt::Debug for SyncStatus {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "Dapps Sync Status")
|
||||
}
|
||||
}
|
||||
impl node_health::SyncStatus for SyncStatus {
|
||||
fn is_major_importing(&self) -> bool {
|
||||
is_major_importing(Some(self.0.status().state), self.1.queue_info())
|
||||
}
|
||||
fn peers(&self) -> (usize, usize) {
|
||||
let status = self.0.status();
|
||||
(status.num_peers, status.current_max_peers(self.2.min_peers, self.2.max_peers) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
let sync_status = Arc::new(SyncStatus(sync, client, net_conf));
|
||||
node_health::NodeHealth::new(
|
||||
sync_status.clone(),
|
||||
node_health::TimeChecker::new(&cmd.ntp_servers, cpu_pool.clone()),
|
||||
event_loop.remote(),
|
||||
)
|
||||
};
|
||||
|
||||
let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies {
|
||||
signer_service: signer_service,
|
||||
snapshot: snapshot_service.clone(),
|
||||
client: client.clone(),
|
||||
sync: sync_provider.clone(),
|
||||
health: node_health,
|
||||
net: manage_network.clone(),
|
||||
secret_store: secret_store,
|
||||
miner: miner.clone(),
|
||||
@@ -821,13 +766,13 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
user_defaults.pruning = algorithm;
|
||||
user_defaults.tracing = tracing;
|
||||
user_defaults.fat_db = fat_db;
|
||||
user_defaults.mode = mode;
|
||||
user_defaults.set_mode(mode);
|
||||
user_defaults.save(&user_defaults_path)?;
|
||||
|
||||
// tell client how to save the default mode if it gets changed.
|
||||
client.on_user_defaults_change(move |mode: Option<Mode>| {
|
||||
if let Some(mode) = mode {
|
||||
user_defaults.mode = mode;
|
||||
user_defaults.set_mode(mode);
|
||||
}
|
||||
let _ = user_defaults.save(&user_defaults_path); // discard failures - there's nothing we can do
|
||||
});
|
||||
|
||||
@@ -14,107 +14,130 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::collections::BTreeMap;
|
||||
use std::time::Duration;
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
use serde::de::{Error, Visitor, MapAccess};
|
||||
use serde::de::value::MapAccessDeserializer;
|
||||
use serde_json::Value;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_json::de::from_reader;
|
||||
use serde_json::ser::to_string;
|
||||
use journaldb::Algorithm;
|
||||
use ethcore::client::Mode;
|
||||
use ethcore::client::{Mode as ClientMode};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Seconds(Duration);
|
||||
|
||||
impl Seconds {
|
||||
pub fn value(&self) -> u64 {
|
||||
self.0.as_secs()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Seconds {
|
||||
fn from(s: u64) -> Seconds {
|
||||
Seconds(Duration::from_secs(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for Seconds {
|
||||
fn from(d: Duration) -> Seconds {
|
||||
Seconds(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Duration> for Seconds {
|
||||
fn into(self) -> Duration {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Seconds {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_u64(self.value())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Seconds {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
let secs = u64::deserialize(deserializer)?;
|
||||
Ok(Seconds::from(secs))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase", tag = "mode")]
|
||||
pub enum Mode {
|
||||
Active,
|
||||
Passive {
|
||||
#[serde(rename = "mode.timeout")]
|
||||
timeout: Seconds,
|
||||
#[serde(rename = "mode.alarm")]
|
||||
alarm: Seconds,
|
||||
},
|
||||
Dark {
|
||||
#[serde(rename = "mode.timeout")]
|
||||
timeout: Seconds,
|
||||
},
|
||||
Offline,
|
||||
}
|
||||
|
||||
impl Into<ClientMode> for Mode {
|
||||
fn into(self) -> ClientMode {
|
||||
match self {
|
||||
Mode::Active => ClientMode::Active,
|
||||
Mode::Passive { timeout, alarm } => ClientMode::Passive(timeout.into(), alarm.into()),
|
||||
Mode::Dark { timeout } => ClientMode::Dark(timeout.into()),
|
||||
Mode::Offline => ClientMode::Off,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClientMode> for Mode {
|
||||
fn from(mode: ClientMode) -> Mode {
|
||||
match mode {
|
||||
ClientMode::Active => Mode::Active,
|
||||
ClientMode::Passive(timeout, alarm) => Mode::Passive { timeout: timeout.into(), alarm: alarm.into() },
|
||||
ClientMode::Dark(timeout) => Mode::Dark { timeout: timeout.into() },
|
||||
ClientMode::Off => Mode::Offline,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UserDefaults {
|
||||
pub is_first_launch: bool,
|
||||
#[serde(with = "algorithm_serde")]
|
||||
pub pruning: Algorithm,
|
||||
pub tracing: bool,
|
||||
pub fat_db: bool,
|
||||
pub mode: Mode,
|
||||
#[serde(flatten)]
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
impl Serialize for UserDefaults {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
impl UserDefaults {
|
||||
pub fn mode(&self) -> ClientMode {
|
||||
self.mode.clone().into()
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: ClientMode) {
|
||||
self.mode = mode.into();
|
||||
}
|
||||
}
|
||||
|
||||
mod algorithm_serde {
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::Error;
|
||||
use journaldb::Algorithm;
|
||||
|
||||
pub fn serialize<S>(algorithm: &Algorithm, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer {
|
||||
let mut map: BTreeMap<String, Value> = BTreeMap::new();
|
||||
map.insert("is_first_launch".into(), Value::Bool(self.is_first_launch));
|
||||
map.insert("pruning".into(), Value::String(self.pruning.as_str().into()));
|
||||
map.insert("tracing".into(), Value::Bool(self.tracing));
|
||||
map.insert("fat_db".into(), Value::Bool(self.fat_db));
|
||||
let mode_str = match self.mode {
|
||||
Mode::Off => "offline",
|
||||
Mode::Dark(timeout) => {
|
||||
map.insert("mode.timeout".into(), Value::Number(timeout.as_secs().into()));
|
||||
"dark"
|
||||
},
|
||||
Mode::Passive(timeout, alarm) => {
|
||||
map.insert("mode.timeout".into(), Value::Number(timeout.as_secs().into()));
|
||||
map.insert("mode.alarm".into(), Value::Number(alarm.as_secs().into()));
|
||||
"passive"
|
||||
},
|
||||
Mode::Active => "active",
|
||||
};
|
||||
map.insert("mode".into(), Value::String(mode_str.into()));
|
||||
|
||||
map.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
struct UserDefaultsVisitor;
|
||||
|
||||
impl<'a> Deserialize<'a> for UserDefaults {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'a> {
|
||||
deserializer.deserialize_any(UserDefaultsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for UserDefaultsVisitor {
|
||||
type Value = UserDefaults;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a valid UserDefaults object")
|
||||
algorithm.as_str().serialize(serializer)
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error> where V: MapAccess<'a> {
|
||||
let mut map: BTreeMap<String, Value> = Deserialize::deserialize(MapAccessDeserializer::new(visitor))?;
|
||||
let pruning: Value = map.remove("pruning").ok_or_else(|| Error::custom("missing pruning"))?;
|
||||
let pruning = pruning.as_str().ok_or_else(|| Error::custom("invalid pruning value"))?;
|
||||
let pruning = pruning.parse().map_err(|_| Error::custom("invalid pruning method"))?;
|
||||
let tracing: Value = map.remove("tracing").ok_or_else(|| Error::custom("missing tracing"))?;
|
||||
let tracing = tracing.as_bool().ok_or_else(|| Error::custom("invalid tracing value"))?;
|
||||
let fat_db: Value = map.remove("fat_db").unwrap_or_else(|| Value::Bool(false));
|
||||
let fat_db = fat_db.as_bool().ok_or_else(|| Error::custom("invalid fat_db value"))?;
|
||||
|
||||
let mode: Value = map.remove("mode").unwrap_or_else(|| Value::String("active".to_owned()));
|
||||
let mode = match mode.as_str().ok_or_else(|| Error::custom("invalid mode value"))? {
|
||||
"offline" => Mode::Off,
|
||||
"dark" => {
|
||||
let timeout = map.remove("mode.timeout").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.timeout value"))?;
|
||||
Mode::Dark(Duration::from_secs(timeout))
|
||||
},
|
||||
"passive" => {
|
||||
let timeout = map.remove("mode.timeout").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.timeout value"))?;
|
||||
let alarm = map.remove("mode.alarm").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.alarm value"))?;
|
||||
Mode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm))
|
||||
},
|
||||
"active" => Mode::Active,
|
||||
_ => { return Err(Error::custom("invalid mode value")); },
|
||||
};
|
||||
|
||||
let user_defaults = UserDefaults {
|
||||
is_first_launch: false,
|
||||
pruning: pruning,
|
||||
tracing: tracing,
|
||||
fat_db: fat_db,
|
||||
mode: mode,
|
||||
};
|
||||
|
||||
Ok(user_defaults)
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Algorithm, D::Error>
|
||||
where D: Deserializer<'de> {
|
||||
let pruning = String::deserialize(deserializer)?;
|
||||
pruning.parse().map_err(|_| Error::custom("invalid pruning method"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user