diff --git a/.gitignore b/.gitignore index 47546d0ed..e3bb529c4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ out/ .vscode + +parity.* diff --git a/updater/src/lib.rs b/updater/src/lib.rs index bc1d2d2c3..08ed57717 100644 --- a/updater/src/lib.rs +++ b/updater/src/lib.rs @@ -24,5 +24,7 @@ extern crate ethabi; mod updater; mod operations; +mod service; -pub use updater::{Updater, UpdateFilter, UpdatePolicy, ReleaseInfo, OperationsInfo, CapState}; \ No newline at end of file +pub use service::{Service, ReleaseInfo, OperationsInfo, CapState}; +pub use updater::{Updater, UpdateFilter, UpdatePolicy}; \ No newline at end of file diff --git a/updater/src/service.rs b/updater/src/service.rs new file mode 100644 index 000000000..2343a95f7 --- /dev/null +++ b/updater/src/service.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::{H256}; +use util::misc::{VersionInfo}; + +/// Information regarding a particular release of Parity +#[derive(Debug, Clone, PartialEq)] +pub struct ReleaseInfo { + /// Information on the version. + pub version: VersionInfo, + /// Does this release contain critical security updates? + pub is_critical: bool, + /// The latest fork that this release can handle. + pub fork: u64, + /// Our platform's binary, if known. + pub binary: Option, +} + +/// Information on our operations environment. +#[derive(Debug, Clone, PartialEq)] +pub struct OperationsInfo { + /// Our blockchain's latest fork. + pub fork: u64, + + /// Last fork our client supports, if known. + pub this_fork: Option, + + /// Information on our track's latest release. + pub track: ReleaseInfo, + /// Information on our minor version's latest release. + pub minor: Option, +} + +/// Information on the current version's consensus capabililty. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CapState { + /// Unknown. + Unknown, + /// Capable of consensus indefinitely. + Capable, + /// Capable of consensus up until a definite block. + CapableUntil(u64), + /// Incapable of consensus since a particular block. + IncapableSince(u64), +} + +impl Default for CapState { + fn default() -> Self { CapState::Unknown } +} + +pub trait Service: Send + Sync { + /// Is the currently running client capable of supporting the current chain? + /// We default to true if there's no clear information. + fn capability(&self) -> CapState; + + /// The release which is ready to be upgraded to, if any. If this returns `Some`, then + /// `execute_upgrade` may be called. + fn upgrade_ready(&self) -> Option; + + /// Actually upgrades the client. Assumes that the binary has been downloaded. + /// @returns `true` on success. + fn execute_upgrade(&self) -> bool; + + /// Our version info. + fn version_info(&self) -> VersionInfo; + + /// Information gathered concerning the release. + fn info(&self) -> Option; +} + diff --git a/updater/src/updater.rs b/updater/src/updater.rs index b400d5fc8..f0226f9e0 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -23,6 +23,7 @@ use util::{Address, H160, H256, FixedHash, Mutex, Bytes}; use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; use hash_fetch::{self as fetch, HashFetch}; use operations::Operations; +use service::{Service, ReleaseInfo, OperationsInfo, CapState}; /// Filter for releases. #[derive(Debug, Eq, PartialEq, Clone)] @@ -56,51 +57,6 @@ impl Default for UpdatePolicy { } } -/// Information regarding a particular release of Parity -#[derive(Debug, Clone, PartialEq)] -pub struct ReleaseInfo { - /// Information on the version. - pub version: VersionInfo, - /// Does this release contain critical security updates? - pub is_critical: bool, - /// The latest fork that this release can handle. - pub fork: u64, - /// Our platform's binary, if known. - pub binary: Option, -} - -/// Information on our operations environment. -#[derive(Debug, Clone, PartialEq)] -pub struct OperationsInfo { - /// Our blockchain's latest fork. - pub fork: u64, - - /// Last fork our client supports, if known. - pub this_fork: Option, - - /// Information on our track's latest release. - pub track: ReleaseInfo, - /// Information on our minor version's latest release. - pub minor: Option, -} - -/// Information on the current version's consensus capabililty. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum CapState { - /// Unknown. - Unknown, - /// Capable of consensus indefinitely. - Capable, - /// Capable of consensus up until a definite block. - CapableUntil(u64), - /// Incapable of consensus since a particular block. - IncapableSince(u64), -} - -impl Default for CapState { - fn default() -> Self { CapState::Unknown } -} - #[derive(Debug, Default)] struct UpdaterState { latest: Option, @@ -157,60 +113,10 @@ impl Updater { let r = Arc::new(u); *r.fetcher.lock() = Some(fetch::Client::new(r.clone())); *r.weak_self.lock() = Arc::downgrade(&r); - r.poll(); - r } - /// Is the currently running client capable of supporting the current chain? - /// We default to true if there's no clear information. - pub fn capability(&self) -> CapState { - self.state.lock().capability - } - - /// The release which is ready to be upgraded to, if any. If this returns `Some`, then - /// `execute_upgrade` may be called. - pub fn upgrade_ready(&self) -> Option { - self.state.lock().ready.clone() - } - - /// Actually upgrades the client. Assumes that the binary has been downloaded. - /// @returns `true` on success. - pub fn execute_upgrade(&self) -> bool { - (|| -> Result { - let mut s = self.state.lock(); - if let Some(r) = s.ready.take() { - let p = Self::update_file_name(&r.version); - let n = Self::updates_path("latest"); - // TODO: creating then writing is a bit fragile. would be nice to make it atomic. - match fs::File::create(&n).and_then(|mut f| f.write_all(p.as_bytes())) { - Ok(_) => { - info!("Completed upgrade to {}", &r.version); - s.installed = Some(r); - if let Some(ref h) = *self.exit_handler.lock() { - (*h)(); - } - Ok(true) - } - Err(e) => { - s.ready = Some(r); - Err(format!("Unable to create soft-link for update {:?}", e)) - } - } - } else { - warn!("Execute upgrade called when no upgrade ready."); - Ok(false) - } - })().unwrap_or_else(|e| { warn!("{}", e); false }) - } - - /// Our version info. - pub fn version_info(&self) -> &VersionInfo { &self.this } - - /// Information gathered concerning the release. - pub fn info(&self) -> Option { self.state.lock().latest.clone() } - /// Set a closure to call when we want to restart the client pub fn set_exit_handler(&self, f: F) where F: Fn() + 'static + Send { *self.exit_handler.lock() = Some(Box::new(f)); @@ -391,3 +297,45 @@ impl fetch::urlhint::ContractClient for Updater { .call_contract(address, data) } } + +impl Service for Updater { + fn capability(&self) -> CapState { + self.state.lock().capability + } + + fn upgrade_ready(&self) -> Option { + self.state.lock().ready.clone() + } + + fn execute_upgrade(&self) -> bool { + (|| -> Result { + let mut s = self.state.lock(); + if let Some(r) = s.ready.take() { + let p = Self::update_file_name(&r.version); + let n = Self::updates_path("latest"); + // TODO: creating then writing is a bit fragile. would be nice to make it atomic. + match fs::File::create(&n).and_then(|mut f| f.write_all(p.as_bytes())) { + Ok(_) => { + info!("Completed upgrade to {}", &r.version); + s.installed = Some(r); + if let Some(ref h) = *self.exit_handler.lock() { + (*h)(); + } + Ok(true) + } + Err(e) => { + s.ready = Some(r); + Err(format!("Unable to create soft-link for update {:?}", e)) + } + } + } else { + warn!("Execute upgrade called when no upgrade ready."); + Ok(false) + } + })().unwrap_or_else(|e| { warn!("{}", e); false }) + } + + fn version_info(&self) -> VersionInfo { self.this.clone() } + + fn info(&self) -> Option { self.state.lock().latest.clone() } +} \ No newline at end of file