11use crate :: formatter:: { error_without_trace, info, success} ;
22use bytes:: Bytes ;
3+ use log:: error;
34use reqwest:: header:: { ACCEPT , USER_AGENT } ;
5+ use reqwest:: { Client , Response } ;
46use serde:: Deserialize ;
57use std:: fs;
68use std:: fs:: File ;
@@ -17,7 +19,6 @@ struct Release {
1719struct Asset {
1820 name : String ,
1921 browser_download_url : String ,
20- size : u64 ,
2122}
2223
2324pub async fn handle_download ( tag : Option < String > , features : Option < Vec < String > > ) {
@@ -26,13 +27,7 @@ pub async fn handle_download(tag: Option<String>, features: Option<Vec<String>>)
2627
2728 // Download the definitions
2829 info ( "Starting download process..." . to_string ( ) ) ;
29- let bytes = match download_definitions_as_bytes ( tag) . await {
30- Some ( bytes) => bytes,
31- None => {
32- error_without_trace ( String :: from ( "Download failed." ) ) ;
33- return ;
34- }
35- } ;
30+ let bytes = download_definitions_as_bytes ( tag) . await ;
3631
3732 // Extract the zip file
3833 convert_bytes_to_folder ( bytes, zip_path) . await ;
@@ -52,7 +47,8 @@ pub async fn handle_download(tag: Option<String>, features: Option<Vec<String>>)
5247 ) ) ;
5348}
5449
55- async fn download_definitions_as_bytes ( tag : Option < String > ) -> Option < bytes:: Bytes > {
50+ async fn download_definitions_as_bytes ( tag : Option < String > ) -> Bytes {
51+ let max_retries = 3 ;
5652 let client = reqwest:: Client :: new ( ) ;
5753
5854 let url = match tag {
@@ -66,23 +62,46 @@ async fn download_definitions_as_bytes(tag: Option<String>) -> Option<bytes::Byt
6662 }
6763 } ;
6864
69- let release_request = match client
70- . get ( url)
71- . header ( USER_AGENT , "code0-definition-cli" )
72- . header ( ACCEPT , "application/vnd.github+json" )
73- . send ( )
74- . await
75- {
76- Ok ( response) => {
77- if response. status ( ) . is_success ( ) {
78- response
79- } else {
80- return None ;
81- }
65+ async fn download_release ( client : & Client , url : String ) -> Response {
66+ match client
67+ . get ( url)
68+ . header ( USER_AGENT , "code0-definition-cli" )
69+ . header ( ACCEPT , "application/vnd.github+json" )
70+ . send ( )
71+ . await
72+ {
73+ Ok ( r) => r,
74+ Err ( e) => panic ! ( "Request failed: {:?}" , e) ,
8275 }
83- Err ( e) => {
84- panic ! ( "Request failed: {}" , e) ;
76+ }
77+
78+ let mut retries = 0 ;
79+ let mut result = None ;
80+ let mut succeeded = false ;
81+
82+ while !succeeded {
83+ let release_request = download_release ( & client, url. clone ( ) ) . await ;
84+ if release_request. status ( ) . is_success ( ) {
85+ succeeded = true ;
86+ result = Some ( release_request) ;
87+ } else {
88+ if retries >= max_retries {
89+ panic ! ( "Reached max retries while downloading release." )
90+ }
91+
92+ retries += 1 ;
93+ error ! (
94+ "Retrying ({}/{}) download. Failed with status code: {:?}" ,
95+ retries,
96+ max_retries,
97+ release_request. status( )
98+ ) ;
8599 }
100+ }
101+
102+ let release_request = match result {
103+ Some ( r) => r,
104+ None => panic ! ( "Failed to download release" ) ,
86105 } ;
87106
88107 let release: Release = match release_request. json :: < Release > ( ) . await {
@@ -91,7 +110,7 @@ async fn download_definitions_as_bytes(tag: Option<String>) -> Option<bytes::Byt
91110 release
92111 }
93112 Err ( e) => {
94- panic ! ( "Request failed: {}" , e) ;
113+ panic ! ( "Request failed: {:? }" , e) ;
95114 }
96115 } ;
97116
@@ -108,34 +127,53 @@ async fn download_definitions_as_bytes(tag: Option<String>) -> Option<bytes::Byt
108127 }
109128 } ;
110129
111- match client
112- . get ( & asset. browser_download_url )
113- . header ( USER_AGENT , "code0-definition-cli" )
114- . send ( )
115- . await
116- {
117- Ok ( response) => {
118- if response. status ( ) . is_success ( ) {
119- match response. bytes ( ) . await {
120- Ok ( bytes) => {
121- info ( "Download completed successfully" . to_string ( ) ) ;
122- Some ( bytes)
123- }
124- Err ( e) => {
125- error_without_trace ( format ! ( "Failed to read download data: {e}" ) ) ;
126- None
127- }
128- }
129- } else {
130- error_without_trace ( format ! (
131- "Download failed with status: {}" ,
132- response. status( )
133- ) ) ;
134- None
130+ let mut asset_retries = 0 ;
131+ let mut asset_result = None ;
132+ let mut asset_success = false ;
133+
134+ while !asset_success {
135+ let response = match client
136+ . get ( & asset. browser_download_url )
137+ . header ( USER_AGENT , "code0-definition-cli" )
138+ . send ( )
139+ . await
140+ {
141+ Ok ( response) => response,
142+ Err ( e) => {
143+ panic ! ( "Download request failed: {:?}" , e) ;
144+ }
145+ } ;
146+
147+ if response. status ( ) . is_success ( ) {
148+ asset_success = true ;
149+ asset_result = Some ( response) ;
150+ } else {
151+ if asset_retries >= max_retries {
152+ panic ! ( "Reached max retries while downloading asset!" ) ;
135153 }
154+
155+ asset_retries += 1 ;
156+ error ! (
157+ "Retrying ({}/{}) asset download. Failed with status code: {:?}" ,
158+ asset_retries,
159+ max_retries,
160+ response. status( )
161+ ) ;
162+ }
163+ }
164+
165+ let response = match asset_result {
166+ Some ( r) => r,
167+ None => panic ! ( "Failed to download asset!" ) ,
168+ } ;
169+
170+ match response. bytes ( ) . await {
171+ Ok ( bytes) => {
172+ info ( "Download completed successfully" . to_string ( ) ) ;
173+ bytes
136174 }
137175 Err ( e) => {
138- panic ! ( "Download request failed : {e}" ) ;
176+ panic ! ( "Failed to read downloaded data : {:?}" , e ) ;
139177 }
140178 }
141179}
@@ -148,14 +186,14 @@ async fn convert_bytes_to_folder(bytes: Bytes, zip_path: &str) {
148186 let zip_file = match File :: open ( zip_path) {
149187 Ok ( file) => file,
150188 Err ( e) => {
151- panic ! ( "Failed to open zip file: {e}" ) ;
189+ panic ! ( "Failed to open zip file: {:?}" , e ) ;
152190 }
153191 } ;
154192
155193 let mut archive = match ZipArchive :: new ( zip_file) {
156194 Ok ( archive) => archive,
157195 Err ( e) => {
158- panic ! ( "Failed to read zip archive: {e}" ) ;
196+ panic ! ( "Failed to read zip archive: {:?}" , e ) ;
159197 }
160198 } ;
161199
@@ -166,7 +204,7 @@ async fn convert_bytes_to_folder(bytes: Bytes, zip_path: &str) {
166204 let mut file = match archive. by_index ( i) {
167205 Ok ( file) => file,
168206 Err ( e) => {
169- panic ! ( "Failed to read file at index {i}: {e}" ) ;
207+ panic ! ( "Failed to read file at index {i}: {:?}" , e ) ;
170208 }
171209 } ;
172210
@@ -177,15 +215,15 @@ async fn convert_bytes_to_folder(bytes: Bytes, zip_path: &str) {
177215
178216 if file. name ( ) . ends_with ( '/' ) {
179217 if let Err ( e) = fs:: create_dir_all ( & out_path) {
180- panic ! ( "Failed to create directory {}: {}" , out_path. display( ) , e) ;
218+ panic ! ( "Failed to create directory {}: {:? }" , out_path. display( ) , e) ;
181219 }
182220 } else {
183221 if let Some ( p) = out_path. parent ( )
184222 && !p. exists ( )
185223 && let Err ( e) = fs:: create_dir_all ( p)
186224 {
187225 panic ! (
188- "Warning: Failed to create parent directory {}: {}" ,
226+ "Warning: Failed to create parent directory {}: {:? }" ,
189227 p. display( ) ,
190228 e
191229 ) ;
@@ -194,11 +232,11 @@ async fn convert_bytes_to_folder(bytes: Bytes, zip_path: &str) {
194232 match File :: create ( & out_path) {
195233 Ok ( mut outfile) => {
196234 if let Err ( e) = std:: io:: copy ( & mut file, & mut outfile) {
197- panic ! ( "Warning: Failed to extract {}: {}" , out_path. display( ) , e) ;
235+ panic ! ( "Warning: Failed to extract {}: {:? }" , out_path. display( ) , e) ;
198236 }
199237 }
200238 Err ( e) => {
201- panic ! ( "Failed to create file {}: {}" , out_path. display( ) , e) ;
239+ panic ! ( "Failed to create file {}: {:? }" , out_path. display( ) , e) ;
202240 }
203241 }
204242 }
@@ -209,40 +247,41 @@ async fn convert_bytes_to_folder(bytes: Bytes, zip_path: &str) {
209247
210248 match fs:: remove_file ( zip_path) {
211249 Ok ( _) => info ( "Temporary zip file removed" . to_string ( ) ) ,
212- Err ( e) => error_without_trace ( format ! ( "Warning: Failed to remove temporary zip file: {e}" ) ) ,
250+ Err ( e) => error_without_trace ( format ! (
251+ "Warning: Failed to remove temporary zip file: {:?}" ,
252+ e
253+ ) ) ,
213254 }
214255}
215256
216257async fn filter_features ( selected_features : Vec < String > ) {
217258 let definitions_path = "./definitions" ;
218259
219- match fs:: read_dir ( definitions_path) {
220- Ok ( entries) => {
221- for entry in entries {
222- let directory = match entry {
223- Ok ( directory) => directory,
224- Err ( e) => {
225- panic ! (
226- "{}" ,
227- format!( "Warning: Failed to read directory entry: {e}" )
228- ) ;
229- }
230- } ;
260+ let entries = match fs:: read_dir ( definitions_path) {
261+ Ok ( entries) => entries,
262+ Err ( e) => {
263+ error_without_trace ( format ! ( "Failed to read definitions directory: {:?}" , e) ) ;
264+ return ;
265+ }
266+ } ;
231267
232- let name = directory. file_name ( ) . to_str ( ) . unwrap_or ( "" ) . to_string ( ) ;
268+ for entry in entries {
269+ let directory = match entry {
270+ Ok ( directory) => directory,
271+ Err ( e) => {
272+ panic ! ( "Warning: Failed to read directory entry {:?}" , e) ;
273+ }
274+ } ;
233275
234- if !selected_features . contains ( & name ) {
235- match fs :: remove_dir_all ( directory . path ( ) ) {
236- Ok ( _ ) => { }
237- Err ( e ) => {
238- error_without_trace ( format ! ( "Warning: Failed to remove directory: {e}" ) )
239- }
240- }
276+ let name = directory . file_name ( ) . to_str ( ) . unwrap_or ( "" ) . to_string ( ) ;
277+
278+ if !selected_features . contains ( & name ) {
279+ match fs :: remove_dir_all ( directory . path ( ) ) {
280+ Ok ( _ ) => { }
281+ Err ( e ) => {
282+ error_without_trace ( format ! ( "Warning: Failed to remove directory: {:?}" , e ) )
241283 }
242284 }
243285 }
244- Err ( e) => {
245- error_without_trace ( format ! ( "Failed to read definitions directory: {e}" ) ) ;
246- }
247286 }
248287}
0 commit comments