2016-11-18 12:14:52 +01:00
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
2016-11-30 10:16:18 +01:00
use std ::sync ::{ Weak , Arc } ;
2016-11-25 19:29:13 +01:00
use std ::path ::PathBuf ;
2016-11-22 10:24:22 +01:00
use util ::misc ::{ VersionInfo , ReleaseTrack , platform } ;
2016-11-30 10:16:18 +01:00
use util ::{ Bytes , Address , H160 , H256 , FixedHash , Mutex } ;
2016-11-18 12:14:52 +01:00
use client ::operations ::Operations ;
2016-11-25 19:29:13 +01:00
use client ::{ Client , BlockChainClient , UpdatePolicy , BlockId } ;
use fetch ::HashFetch ;
use fetch ;
2016-11-22 10:24:22 +01:00
2016-11-25 15:43:49 +01:00
#[ derive(Debug, Clone, PartialEq) ]
2016-11-22 10:24:22 +01:00
pub struct ReleaseInfo {
2016-11-25 15:43:49 +01:00
pub version : VersionInfo ,
pub is_critical : bool ,
pub fork : u64 ,
pub binary : Option < H256 > ,
}
#[ derive(Debug, Clone, PartialEq) ]
pub struct OperationsInfo {
pub fork : u64 ,
2016-11-22 10:24:22 +01:00
2016-11-25 15:43:49 +01:00
pub track : ReleaseInfo ,
pub minor : Option < ReleaseInfo > ,
2016-11-22 10:24:22 +01:00
}
2016-11-18 12:14:52 +01:00
pub struct Updater {
2016-11-22 10:24:22 +01:00
client : Weak < Client > ,
2016-11-30 10:16:18 +01:00
fetch : Weak < HashFetch > ,
2016-11-18 12:14:52 +01:00
operations : Operations ,
2016-11-24 17:19:48 +01:00
update_policy : UpdatePolicy ,
2016-11-30 10:16:18 +01:00
fetch_handler : Mutex < Option < ( ) > > ,
2016-11-18 12:14:52 +01:00
2016-11-25 15:43:49 +01:00
// These don't change
2016-11-22 10:24:22 +01:00
pub this : VersionInfo ,
2016-11-25 15:43:49 +01:00
pub this_fork : Option < u64 > ,
// This does change
pub latest : Option < OperationsInfo > ,
2016-11-20 13:18:56 +01:00
}
2016-11-25 15:43:49 +01:00
const CLIENT_ID : & 'static str = " parity " ;
2016-11-30 10:16:18 +01:00
fn start_fetch ( fetch : Arc < HashFetch > , hash : H256 , on_done : Box < Fn ( Result < PathBuf , fetch ::Error > ) + Send > ) -> Result < ( ) , fetch ::Error > {
fetch . fetch ( hash , on_done )
2016-11-25 19:29:13 +01:00
}
2016-11-18 12:14:52 +01:00
impl Updater {
2016-11-30 10:16:18 +01:00
pub fn new ( client : Weak < Client > , fetch : Weak < fetch ::Client > , operations : Address , update_policy : UpdatePolicy ) -> Self {
2016-11-22 10:24:22 +01:00
let mut u = Updater {
client : client . clone ( ) ,
2016-11-30 10:16:18 +01:00
fetch : fetch . clone ( ) ,
2016-11-18 12:14:52 +01:00
operations : Operations ::new ( operations , move | a , d | client . upgrade ( ) . ok_or ( " No client! " . into ( ) ) . and_then ( | c | c . call_contract ( a , d ) ) ) ,
2016-11-24 17:19:48 +01:00
update_policy : update_policy ,
2016-11-25 19:29:13 +01:00
fetch_handler : Mutex ::new ( None ) ,
2016-11-22 10:24:22 +01:00
this : VersionInfo ::this ( ) ,
2016-11-24 17:19:48 +01:00
this_fork : None ,
2016-11-25 15:43:49 +01:00
latest : None ,
2016-11-22 10:24:22 +01:00
} ;
2016-11-24 17:19:48 +01:00
2016-11-25 15:43:49 +01:00
u . this_fork = u . operations . release ( CLIENT_ID , & u . this . hash . into ( ) ) . ok ( )
. and_then ( | ( fork , track , _ , _ ) | if track > 0 { Some ( fork as u64 ) } else { None } ) ;
2016-11-24 17:19:48 +01:00
// TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! REMOVE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2016-11-22 10:24:22 +01:00
if u . this . track = = ReleaseTrack ::Unknown {
u . this . track = ReleaseTrack ::Nightly ;
2016-11-24 17:19:48 +01:00
}
2016-11-25 15:43:49 +01:00
u . latest = u . collect_latest ( ) . ok ( ) ;
2016-11-22 10:24:22 +01:00
u
2016-11-18 12:14:52 +01:00
}
2016-11-24 17:19:48 +01:00
/// Is the currently running client capable of supporting the current chain?
2016-11-30 10:16:18 +01:00
/// `Some` answer or `None` if information on the running client is not available.
2016-11-24 17:19:48 +01:00
pub fn is_capable ( & self ) -> Option < bool > {
2016-11-25 15:43:49 +01:00
self . latest . as_ref ( ) . and_then ( | latest | {
self . this_fork . map ( | this_fork | {
2016-11-24 17:19:48 +01:00
let current_number = self . client . upgrade ( ) . map_or ( 0 , | c | c . block_number ( BlockId ::Latest ) . unwrap_or ( 0 ) ) ;
2016-11-30 10:16:18 +01:00
this_fork > = latest . fork | | current_number < latest . fork
2016-11-24 17:19:48 +01:00
} )
} )
}
/// 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 < VersionInfo > {
unimplemented! ( )
}
/// Actually upgrades the client. Assumes that the binary has been downloaded.
2016-11-30 10:16:18 +01:00
/// @returns `true` on success.
2016-11-24 17:19:48 +01:00
pub fn execute_upgrade ( & mut self ) -> bool {
unimplemented! ( )
}
2016-11-30 10:16:18 +01:00
/// Our version info.
2016-11-25 15:43:49 +01:00
pub fn version_info ( & self ) -> & VersionInfo { & self . this }
2016-11-24 17:19:48 +01:00
2016-11-30 10:16:18 +01:00
/// Information gathered concerning the release.
2016-11-25 15:43:49 +01:00
pub fn info ( & self ) -> & Option < OperationsInfo > { & self . latest }
2016-11-24 17:19:48 +01:00
2016-11-25 15:43:49 +01:00
fn collect_release_info ( & self , release_id : & H256 ) -> Result < ReleaseInfo , String > {
let ( fork , track , semver , is_critical ) = self . operations . release ( CLIENT_ID , release_id ) ? ;
let latest_binary = self . operations . checksum ( CLIENT_ID , release_id , & platform ( ) ) ? ;
Ok ( ReleaseInfo {
version : VersionInfo ::from_raw ( semver , track , release_id . clone ( ) . into ( ) ) ,
is_critical : is_critical ,
fork : fork as u64 ,
binary : if latest_binary . is_zero ( ) { None } else { Some ( latest_binary ) } ,
} )
}
fn collect_latest ( & self ) -> Result < OperationsInfo , String > {
2016-11-22 10:24:22 +01:00
if self . this . track = = ReleaseTrack ::Unknown {
return Err ( format! ( " Current executable ( {} ) is unreleased. " , H160 ::from ( self . this . hash ) ) ) ;
}
2016-11-20 13:18:56 +01:00
2016-11-25 15:43:49 +01:00
let latest_in_track = self . operations . latest_in_track ( CLIENT_ID , self . this . track . into ( ) ) ? ;
let in_track = self . collect_release_info ( & latest_in_track ) ? ;
let mut in_minor = Some ( in_track . clone ( ) ) ;
const PROOF : & 'static str = " in_minor initialised and assigned with Some; loop breaks if None assigned; qed " ;
while in_minor . as_ref ( ) . expect ( PROOF ) . version . track ! = self . this . track {
let track = match in_minor . as_ref ( ) . expect ( PROOF ) . version . track {
ReleaseTrack ::Beta = > ReleaseTrack ::Stable ,
ReleaseTrack ::Nightly = > ReleaseTrack ::Beta ,
_ = > { in_minor = None ; break ; }
} ;
in_minor = Some ( self . collect_release_info ( & self . operations . latest_in_track ( CLIENT_ID , track . into ( ) ) ? ) ? ) ;
}
2016-11-24 17:19:48 +01:00
2016-11-25 15:43:49 +01:00
Ok ( OperationsInfo {
fork : self . operations . latest_fork ( ) ? as u64 ,
track : in_track ,
minor : in_minor ,
2016-11-22 10:24:22 +01:00
} )
}
2016-11-20 13:18:56 +01:00
2016-11-25 19:29:13 +01:00
fn fetch_done ( & self , _r : Result < PathBuf , fetch ::Error > ) {
2016-11-30 10:16:18 +01:00
* self . fetch_handler . lock ( ) = None ;
2016-11-25 19:29:13 +01:00
}
2016-11-22 10:24:22 +01:00
pub fn tick ( & mut self ) {
info! ( target : " updater " , " Current release is {} " , self . this ) ;
2016-11-25 15:43:49 +01:00
self . latest = self . collect_latest ( ) . ok ( ) ;
let current_number = self . client . upgrade ( ) . map_or ( 0 , | c | c . block_number ( BlockId ::Latest ) . unwrap_or ( 0 ) ) ;
if let Some ( ref latest ) = self . latest {
info! ( target : " updater " , " Latest release in our track is v{} it is {}critical ({} binary is {}) " ,
latest . track . version ,
2016-11-30 10:16:18 +01:00
if latest . track . is_critical { " " } else { " non- " } ,
2016-11-22 10:24:22 +01:00
platform ( ) ,
2016-11-25 15:43:49 +01:00
if let Some ( ref b ) = latest . track . binary {
2016-11-22 10:24:22 +01:00
format! ( " {} " , b )
} else {
" unreleased " . into ( )
}
) ;
2016-11-25 19:29:13 +01:00
if let Some ( b ) = latest . track . binary {
2016-11-30 10:16:18 +01:00
let mut fetch_handler = self . fetch_handler . lock ( ) ;
if fetch_handler . is_none ( ) {
let c = self . client . clone ( ) ;
let f = move | r : Result < PathBuf , fetch ::Error > | if let Some ( c ) = c . upgrade ( ) { c . updater ( ) . as_ref ( ) . expect ( " updater exists; updater only owned by client; qed " ) . fetch_done ( r ) ; } ;
if let Some ( fetch ) = self . fetch . clone ( ) . upgrade ( ) {
* fetch_handler = start_fetch ( fetch , b , Box ::new ( f ) ) . ok ( ) ;
2016-11-25 19:29:13 +01:00
}
}
}
2016-11-25 15:43:49 +01:00
info! ( target : " updater " , " Fork: this/current/latest/latest-known: {}/#{}/#{}/#{} " , match self . this_fork { Some ( f ) = > format! ( " # {} " , f ) , None = > " unknown " . into ( ) , } , current_number , latest . track . fork , latest . fork ) ;
2016-11-22 10:24:22 +01:00
}
2016-11-18 12:14:52 +01:00
}
}