@@ -11,7 +11,7 @@ mod auditor;
1111
1212use akd:: local_auditing:: AuditBlobName ;
1313use anyhow:: { anyhow, bail, Result } ;
14- use clap:: Parser ;
14+ use clap:: { Parser , Subcommand } ;
1515use dialoguer:: theme:: ColorfulTheme ;
1616use dialoguer:: { Input , Select } ;
1717use indicatif:: { ProgressBar , ProgressStyle } ;
@@ -45,15 +45,27 @@ impl TryFrom<&str> for EpochSummary {
4545}
4646
4747#[ derive( Parser , Debug , Clone ) ]
48+ #[ clap( author, about, long_about = None ) ]
4849pub ( crate ) struct CliArgs {
49- /// Optional argument to indicate that only the latest epoch should be audited
50+ /// The type of command to run
51+ #[ clap( subcommand) ]
52+ command : Command ,
53+ }
54+
55+ #[ derive( Debug , Clone , Subcommand ) ]
56+ enum Command {
57+ /// For auditing a specific epoch
58+ #[ clap( short_flag = 'e' , name = "Choose a specific epoch to audit" ) ]
59+ Epoch { epoch : u64 } ,
60+ /// For auditing all epochs through an interactive interface
5061 #[ clap(
51- long = "latest" ,
52- short = 'l' ,
53- name = "Audit only the latest epoch" ,
54- default_value = "false"
62+ short_flag = 'i' ,
63+ name = "Load all epochs to be audited (this can take some time...)"
5564 ) ]
56- audit_latest : bool ,
65+ Interactive ,
66+ /// Indicate that only the latest epoch should be audited
67+ #[ clap( short_flag = 'l' , name = "Audit only the latest epoch" ) ]
68+ AuditLatest ,
5769}
5870
5971#[ derive( Debug ) ]
@@ -68,82 +80,96 @@ struct CliOption {
6880}
6981
7082pub ( crate ) async fn render_cli ( args : CliArgs ) -> Result < ( ) > {
71- let pb = start_progress_bar ( "Loading epochs..." ) ;
72- let mut proofs = auditor:: list_proofs ( WHATSAPP_KT_DOMAIN ) . await ?;
73- finish_progress_bar ( pb, auditor:: display_audit_proofs_info ( & mut proofs) ?) ;
74-
75- if args. audit_latest {
76- // Just audit the latest epoch and exit
77- let latest_epoch_summary = proofs. last ( ) . expect ( "No epochs found" ) ;
78- do_epoch_audit ( latest_epoch_summary) . await ?;
79- return Ok ( ( ) ) ;
80- }
81-
82- let items: Vec < CliOption > = vec ! [
83- CliOption {
84- cli_type: CliType :: Audit ,
85- text: "Audit" . to_string( ) ,
86- } ,
87- CliOption {
88- cli_type: CliType :: Quit ,
89- text: "Quit" . to_string( ) ,
90- } ,
91- ] ;
92-
93- loop {
94- let selection = Select :: with_theme ( & ColorfulTheme :: default ( ) )
95- . items (
96- & items
97- . iter ( )
98- . map ( |item| item. text . clone ( ) )
99- . collect :: < Vec < String > > ( ) ,
100- )
101- . default ( 0 )
102- . interact_opt ( ) ?;
103-
104- match selection {
105- Some ( index) => match items[ index] . cli_type {
106- CliType :: Audit => {
107- let epoch_input: String = Input :: new ( )
108- . with_prompt ( "Audit which epoch?" . to_string ( ) )
109- . validate_with ( |input : & String | -> Result < ( ) , & str > {
110- let int = input. parse :: < usize > ( ) . map_err ( |_| "Not a valid epoch" ) ?;
111- if 1 <= int && int <= proofs. len ( ) {
112- Ok ( ( ) )
113- } else {
114- Err ( "Epoch is out of available range" )
115- }
116- } )
117- . interact_text ( ) ?;
118- let epoch = epoch_input. parse :: < u64 > ( ) ?;
119- let maybe_proof = proofs. iter ( ) . find ( |proof| proof. name . epoch == epoch) ;
120- if let Some ( epoch_summary) = maybe_proof {
121- do_epoch_audit ( epoch_summary) . await ?;
122- } else {
123- bail ! ( "Could not find epoch {}" , epoch) ;
83+ match args. command {
84+ Command :: AuditLatest => {
85+ // Just audit the latest epoch and exit
86+ let proofs = load_all_proofs ( ) . await ?;
87+ let latest_epoch_summary = proofs. last ( ) . expect ( "No epochs found" ) ;
88+ do_epoch_audit ( latest_epoch_summary) . await ?;
89+ return Ok ( ( ) ) ;
90+ }
91+ Command :: Epoch { epoch } => {
92+ let epoch_summary = auditor:: get_proof_from_epoch ( WHATSAPP_KT_DOMAIN , epoch) . await ?;
93+ do_epoch_audit ( & epoch_summary) . await ?;
94+ return Ok ( ( ) ) ;
95+ }
96+ Command :: Interactive => {
97+ let proofs = load_all_proofs ( ) . await ?;
98+ let items: Vec < CliOption > = vec ! [
99+ CliOption {
100+ cli_type: CliType :: Audit ,
101+ text: "Audit" . to_string( ) ,
102+ } ,
103+ CliOption {
104+ cli_type: CliType :: Quit ,
105+ text: "Quit" . to_string( ) ,
106+ } ,
107+ ] ;
108+
109+ loop {
110+ let selection = Select :: with_theme ( & ColorfulTheme :: default ( ) )
111+ . items (
112+ & items
113+ . iter ( )
114+ . map ( |item| item. text . clone ( ) )
115+ . collect :: < Vec < String > > ( ) ,
116+ )
117+ . default ( 0 )
118+ . interact_opt ( ) ?;
119+
120+ match selection {
121+ Some ( index) => match items[ index] . cli_type {
122+ CliType :: Audit => {
123+ let epoch_input: String = Input :: new ( )
124+ . with_prompt ( "Audit which epoch?" . to_string ( ) )
125+ . validate_with ( |input : & String | -> Result < ( ) , & str > {
126+ let int =
127+ input. parse :: < usize > ( ) . map_err ( |_| "Not a valid epoch" ) ?;
128+ if 1 <= int && int <= proofs. len ( ) {
129+ Ok ( ( ) )
130+ } else {
131+ Err ( "Epoch is out of available range" )
132+ }
133+ } )
134+ . interact_text ( ) ?;
135+ let epoch = epoch_input. parse :: < u64 > ( ) ?;
136+ let maybe_proof = proofs. iter ( ) . find ( |proof| proof. name . epoch == epoch) ;
137+ let Some ( epoch_summary) = maybe_proof else {
138+ bail ! ( "Could not find epoch {epoch}" ) ;
139+ } ;
140+ do_epoch_audit ( epoch_summary) . await ?;
141+ }
142+ CliType :: Quit => {
143+ break ;
144+ }
145+ } ,
146+ None => {
147+ break ;
124148 }
125149 }
126- CliType :: Quit => {
127- break ;
128- }
129- } ,
130- None => {
131- break ;
132150 }
133151 }
134152 }
135153
136154 Ok ( ( ) )
137155}
138156
157+ async fn load_all_proofs ( ) -> Result < Vec < EpochSummary > > {
158+ let pb = start_progress_bar ( "Loading epochs..." ) ;
159+ let mut proofs = auditor:: list_proofs ( WHATSAPP_KT_DOMAIN ) . await ?;
160+ finish_progress_bar ( pb, auditor:: display_audit_proofs_info ( & mut proofs) ?) ;
161+ Ok ( proofs)
162+ }
163+
139164pub ( crate ) async fn do_epoch_audit ( epoch_summary : & EpochSummary ) -> Result < ( ) > {
140165 let pb1 = start_progress_bar ( "Downloading proof..." ) ;
141166 let proof = auditor:: get_proof ( WHATSAPP_KT_DOMAIN , epoch_summary) . await ?;
142167 finish_progress_bar (
143168 pb1,
144169 format ! (
145- "Successfully downloaded proof for epoch {}." ,
146- epoch_summary. name. epoch
170+ "Successfully downloaded proof for epoch {}. ({})" ,
171+ epoch_summary. name. epoch,
172+ bytesize:: ByteSize :: b( proof. data. len( ) as u64 )
147173 ) ,
148174 ) ;
149175
0 commit comments