@@ -7,6 +7,34 @@ use crate::appimage::AppImage;
77use crate :: error:: { Error , Result } ;
88use crate :: update_info:: UpdateInfo ;
99
10+ #[ derive( Debug ) ]
11+ pub struct UpdateStats {
12+ pub source_path : PathBuf ,
13+ pub source_size : u64 ,
14+ pub target_path : PathBuf ,
15+ pub target_size : u64 ,
16+ pub blocks_reused : usize ,
17+ pub blocks_downloaded : usize ,
18+ pub block_size : usize ,
19+ }
20+
21+ impl UpdateStats {
22+ pub fn bytes_reused ( & self ) -> u64 {
23+ ( self . blocks_reused * self . block_size ) as u64
24+ }
25+
26+ pub fn bytes_downloaded ( & self ) -> u64 {
27+ ( self . blocks_downloaded * self . block_size ) as u64
28+ }
29+
30+ pub fn saved_percentage ( & self ) -> u64 {
31+ if self . target_size == 0 {
32+ return 0 ;
33+ }
34+ ( self . bytes_reused ( ) * 100 / self . target_size ) . min ( 100 )
35+ }
36+ }
37+
1038pub struct Updater {
1139 appimage : AppImage ,
1240 update_info : UpdateInfo ,
@@ -107,15 +135,40 @@ impl Updater {
107135 Ok ( true )
108136 }
109137
110- pub fn perform_update ( & self ) -> Result < PathBuf > {
138+ pub fn source_path ( & self ) -> & Path {
139+ self . appimage . path ( )
140+ }
141+
142+ pub fn source_size ( & self ) -> u64 {
143+ fs:: metadata ( self . appimage . path ( ) )
144+ . map ( |m| m. len ( ) )
145+ . unwrap_or ( 0 )
146+ }
147+
148+ pub fn target_info ( & self ) -> Result < ( PathBuf , u64 ) > {
149+ let ( control, _zsync_url) = self . fetch_control_file ( ) ?;
150+ let output_path = self . resolve_output_path ( & control) ?;
151+ Ok ( ( output_path, control. length ) )
152+ }
153+
154+ pub fn perform_update ( & self ) -> Result < ( PathBuf , UpdateStats ) > {
111155 let ( control, zsync_url) = self . fetch_control_file ( ) ?;
112156 let output_path = self . resolve_output_path ( & control) ?;
113157
114158 if output_path. exists ( ) {
115159 if let Some ( ref expected_sha1) = control. sha1
116160 && self . verify_existing_file ( & output_path, expected_sha1) ?
117161 {
118- return Ok ( output_path) ;
162+ let stats = UpdateStats {
163+ source_path : self . appimage . path ( ) . to_path_buf ( ) ,
164+ source_size : self . source_size ( ) ,
165+ target_path : output_path. clone ( ) ,
166+ target_size : control. length ,
167+ blocks_reused : 0 ,
168+ blocks_downloaded : 0 ,
169+ block_size : control. blocksize ,
170+ } ;
171+ return Ok ( ( output_path, stats) ) ;
119172 }
120173
121174 if !self . overwrite {
@@ -130,20 +183,25 @@ impl Updater {
130183 . map ( |m| m. permissions ( ) )
131184 . ok ( ) ;
132185
186+ let source_size = self . source_size ( ) ;
187+ let target_size = control. length ;
188+ let block_size = control. blocksize ;
189+
133190 let assembly = ZsyncAssembly :: from_url ( & zsync_url, & output_path)
134191 . map_err ( |e| Error :: Zsync ( format ! ( "Failed to initialize zsync: {}" , e) ) ) ?;
135192
136193 let mut assembly = assembly;
137194
138- assembly
195+ let blocks_reused = assembly
139196 . submit_source_file ( self . appimage . path ( ) )
140197 . map_err ( |e| Error :: Zsync ( format ! ( "Failed to submit source file: {}" , e) ) ) ?;
141198
142- assembly
199+ let self_blocks = assembly
143200 . submit_self_referential ( )
144201 . map_err ( |e| Error :: Zsync ( format ! ( "Self-referential scan failed: {}" , e) ) ) ?;
202+ let blocks_reused = blocks_reused. saturating_add ( self_blocks) ;
145203
146- assembly
204+ let blocks_downloaded = assembly
147205 . download_missing_blocks ( )
148206 . map_err ( |e| Error :: Zsync ( format ! ( "Failed to download blocks: {}" , e) ) ) ?;
149207
@@ -155,7 +213,17 @@ impl Updater {
155213 fs:: set_permissions ( & output_path, perms) ?;
156214 }
157215
158- Ok ( output_path)
216+ let stats = UpdateStats {
217+ source_path : self . appimage . path ( ) . to_path_buf ( ) ,
218+ source_size,
219+ target_path : output_path. clone ( ) ,
220+ target_size,
221+ blocks_reused,
222+ blocks_downloaded,
223+ block_size,
224+ } ;
225+
226+ Ok ( ( output_path, stats) )
159227 }
160228
161229 pub fn output_path ( & self ) -> Result < PathBuf > {
0 commit comments