1
1
use std:: cell:: RefCell ;
2
+ use std:: collections:: HashMap ;
2
3
use std:: fs;
3
4
use std:: io:: Cursor ;
4
5
use std:: path:: PathBuf ;
5
6
use std:: rc:: Rc ;
6
7
7
- use msfs:: network:: * ;
8
+ use msfs:: { commbus :: * , network:: * } ;
8
9
9
10
use crate :: download:: zip_handler:: ZipFileHandler ;
10
- use crate :: util:: JsonParser ;
11
+
12
+ pub struct DownloadOptions {
13
+ batch_size : usize ,
14
+ }
11
15
12
16
pub struct DownloadStatistics {
13
17
pub total_files : usize ,
@@ -27,42 +31,110 @@ pub enum DownloadStatus {
27
31
pub struct NavdataDownloader {
28
32
zip_handler : RefCell < Option < ZipFileHandler < Cursor < Vec < u8 > > > > > ,
29
33
status : RefCell < DownloadStatus > ,
34
+ options : RefCell < DownloadOptions > ,
30
35
}
31
36
32
37
impl NavdataDownloader {
33
38
pub fn new ( ) -> Self {
34
39
NavdataDownloader {
35
40
zip_handler : RefCell :: new ( None ) ,
36
41
status : RefCell :: new ( DownloadStatus :: NoDownload ) ,
42
+ options : RefCell :: new ( DownloadOptions { batch_size : 10 } ) , // default batch size
43
+ }
44
+ }
45
+
46
+ pub fn on_update ( & self ) {
47
+ let status = self . update_and_get_status ( ) ;
48
+ // If we are extracting, extract the next batch of files
49
+ if status == DownloadStatus :: Extracting {
50
+ // Send the statistics to the JS side
51
+ let statistics: DownloadStatistics = self . get_download_statistics ( ) . unwrap ( ) ;
52
+ let mut map = HashMap :: new ( ) ;
53
+ map. insert ( "total" , statistics. total_files ) ;
54
+ map. insert ( "unzipped" , statistics. files_unzipped ) ;
55
+ let data = serde_json:: to_string ( & map) . unwrap ( ) ;
56
+ CommBus :: call (
57
+ "NAVIGRAPH_UnzippedFilesRemaining" ,
58
+ & data,
59
+ CommBusBroadcastFlags :: All ,
60
+ ) ;
61
+
62
+ // Unzip the next batch of files
63
+ let has_more_files = self . unzip_batch ( 10 ) ;
64
+ if !has_more_files {
65
+ println ! ( "[WASM] finished unzip" ) ;
66
+ CommBus :: call (
67
+ "NAVIGRAPH_NavdataDownloaded" ,
68
+ "" ,
69
+ CommBusBroadcastFlags :: All ,
70
+ ) ;
71
+
72
+ self . clear_zip_handler ( ) ;
73
+ }
74
+ } else if let DownloadStatus :: Failed ( _) = status {
75
+ let error_message = match status {
76
+ DownloadStatus :: Failed ( message) => message,
77
+ _ => "Unknown error" . to_owned ( ) ,
78
+ } ;
79
+ // Send the error message to the JS side
80
+ let mut map = HashMap :: new ( ) ;
81
+ map. insert ( "error" , & error_message) ;
82
+ let data = serde_json:: to_string ( & map) . unwrap ( ) ;
83
+ CommBus :: call (
84
+ "NAVIGRAPH_DownloadFailed" ,
85
+ & data,
86
+ CommBusBroadcastFlags :: All ,
87
+ ) ;
88
+
89
+ self . clear_zip_handler ( ) ;
37
90
}
38
91
}
39
92
40
- pub fn download ( self : & Rc < Self > , args : & [ u8 ] ) {
41
- // Silently fail if we are already downloading
93
+ pub fn set_download_options ( self : & Rc < Self > , args : & str ) {
94
+ // Parse the JSON
95
+ let json_result: Result < serde_json:: Value , serde_json:: Error > = serde_json:: from_str ( args) ;
96
+ if json_result. is_err ( ) {
97
+ println ! (
98
+ "[WASM] Failed to parse JSON: {}" ,
99
+ json_result. err( ) . unwrap( )
100
+ ) ;
101
+ return ;
102
+ }
103
+ let json = json_result. unwrap ( ) ;
104
+ let batch_size = json[ "batchSize" ] . as_u64 ( ) . unwrap_or_default ( ) as usize ;
105
+
106
+ // Set the options (only batch size for now)
107
+ let mut options = self . options . borrow_mut ( ) ;
108
+ options. batch_size = batch_size;
109
+ }
110
+
111
+ pub fn download ( self : & Rc < Self > , args : & str ) {
112
+ // Silently fail if we are already downloading (maybe we should send an error message?)
42
113
if self . update_and_get_status ( ) != DownloadStatus :: NoDownload {
43
114
println ! ( "[WASM] Already downloading" ) ;
44
115
return ;
45
116
}
46
117
47
- // Set our status to downloading (needs to be done in its own scope so that the borrow_mut is dropped)
48
- {
118
+ // Parse the JSON
119
+ let json_result: Result < serde_json:: Value , serde_json:: Error > = serde_json:: from_str ( args) ;
120
+ if json_result. is_ok ( ) {
121
+ // Set our status to downloading (needs to be done in its own scope so that the borrow_mut is dropped)
49
122
let mut status = self . status . borrow_mut ( ) ;
50
123
* status = DownloadStatus :: Downloading ;
51
124
println ! ( "[WASM] Downloading" ) ;
52
- }
53
-
54
- let json_result = JsonParser :: parse ( args) ;
55
- if json_result. is_err ( ) {
125
+ } else {
126
+ // If we failed to parse the JSON, set our status to failed (read above for why this is in its own scope)
56
127
let mut status = self . status . borrow_mut ( ) ;
57
128
let error = json_result. err ( ) . unwrap ( ) ;
58
129
* status = DownloadStatus :: Failed ( format ! ( "JSON Parsing error from JS: {}" , error) ) ;
59
130
println ! ( "[WASM] Failed: {}" , error) ;
60
131
return ;
61
132
}
133
+ // Safe to unwrap since we already checked if it was an error
62
134
let json = json_result. unwrap ( ) ;
63
135
let url = json[ "url" ] . as_str ( ) . unwrap_or_default ( ) ;
64
136
65
- // check if json has "folder"
137
+ // Check if json has "folder"
66
138
let folder = json[ "folder" ] . as_str ( ) . unwrap_or_default ( ) . to_owned ( ) ;
67
139
68
140
let captured_self = self . clone ( ) ;
@@ -76,6 +148,7 @@ impl NavdataDownloader {
76
148
}
77
149
78
150
fn request_finished_callback ( & self , request : NetworkRequest , status_code : i32 , folder : String ) {
151
+ // Fail if the status code is not 200
79
152
if status_code != 200 {
80
153
let mut status = self . status . borrow_mut ( ) ;
81
154
* status = DownloadStatus :: Failed ( format ! (
@@ -85,13 +158,15 @@ impl NavdataDownloader {
85
158
) ) ;
86
159
return ;
87
160
}
161
+ // Create the directory if it doesn't exist
88
162
let path = PathBuf :: from ( format ! ( "\\ work/navdata/{}" , folder) ) ;
89
163
if let Err ( e) = fs:: create_dir_all ( & path) {
90
164
let mut status = self . status . borrow_mut ( ) ;
91
165
* status = DownloadStatus :: Failed ( format ! ( "Failed to create directory: {}" , e) ) ;
92
166
return ;
93
167
}
94
168
169
+ // Check the data from the request
95
170
let data = request. data ( ) ;
96
171
if data. is_none ( ) {
97
172
let mut status = self . status . borrow_mut ( ) ;
@@ -109,10 +184,11 @@ impl NavdataDownloader {
109
184
) ;
110
185
return ;
111
186
}
187
+ // Unwrap is safe since we already checked if it was an error
112
188
let zip = zip. unwrap ( ) ;
113
189
190
+ // Create the zip handler
114
191
let handler = ZipFileHandler :: new ( zip, path) ;
115
-
116
192
let mut zip_handler = self . zip_handler . borrow_mut ( ) ;
117
193
* zip_handler = Some ( handler) ;
118
194
@@ -127,7 +203,7 @@ impl NavdataDownloader {
127
203
pub fn get_download_statistics (
128
204
& self ,
129
205
) -> Result < DownloadStatistics , Box < dyn std:: error:: Error > > {
130
- let zip_handler_ref = self . zip_handler . borrow ( ) ; // Borrow and hold onto the reference
206
+ let zip_handler_ref = self . zip_handler . borrow ( ) ;
131
207
let zip_handler = zip_handler_ref. as_ref ( ) . ok_or ( "No zip handler" ) ?;
132
208
133
209
let total_files = zip_handler. zip_file_count ;
@@ -141,8 +217,9 @@ impl NavdataDownloader {
141
217
} )
142
218
}
143
219
144
- /// This basically either sets the status to no download, extracting, or done
145
220
pub fn update_and_get_status ( & self ) -> DownloadStatus {
221
+ // This basically either sets the status to no download, extracting, or done
222
+
146
223
let mut status = self . status . borrow_mut ( ) ;
147
224
let zip_handler_option = self . zip_handler . borrow ( ) ;
148
225
@@ -166,9 +243,6 @@ impl NavdataDownloader {
166
243
status. clone ( )
167
244
}
168
245
169
- /// Unzips a batch of files
170
- ///
171
- /// Returns true if there are more files to unzip (false if we are done)
172
246
pub fn unzip_batch ( & self , batch_size : usize ) -> bool {
173
247
let mut zip_handler = self . zip_handler . borrow_mut ( ) ;
174
248
match zip_handler. as_mut ( ) {
@@ -186,18 +260,4 @@ impl NavdataDownloader {
186
260
}
187
261
self . update_and_get_status ( ) ;
188
262
}
189
-
190
- pub fn delete_all_files ( & self ) {
191
- // if we are downloading, quietly fail
192
- if self . update_and_get_status ( ) != DownloadStatus :: NoDownload {
193
- println ! ( "[WASM] Cannot delete files while downloading" ) ;
194
- return ;
195
- }
196
- let path = PathBuf :: from ( "\\ work/navdata" ) ;
197
- // iterate through all files in the directory and delete them
198
- match fs:: remove_dir_all ( & path) {
199
- Ok ( _) => ( ) ,
200
- Err ( e) => println ! ( "[WASM] Failed to delete all files: {}" , e) ,
201
- }
202
- }
203
263
}
0 commit comments