1
1
use std:: cell:: Cell ;
2
2
3
+ use anyhow:: Context ;
3
4
use js_sys:: Function ;
4
5
#[ allow( unused_imports, dead_code) ]
5
6
use tracing:: { debug, error, info, trace, warn} ;
@@ -157,48 +158,53 @@ pub async fn fetch(
157
158
}
158
159
159
160
let request = {
160
- let request = Request :: new_with_str_and_init ( & url, & opts)
161
- . map_err ( |_| anyhow:: anyhow!( "Could not construct request object" ) ) ?;
161
+ let request = Request :: new_with_str_and_init ( url, & opts)
162
+ . map_err ( js_error)
163
+ . context ( "Could not construct request object" ) ?;
162
164
163
165
let set_headers = request. headers ( ) ;
164
166
for ( name, val) in headers. iter ( ) {
165
167
let val = String :: from_utf8_lossy ( val. as_bytes ( ) ) ;
166
- set_headers. set ( name. as_str ( ) , & val) . map_err ( |_| {
167
- anyhow:: anyhow!( "could not apply request header: '{name}': '{val}'" )
168
- } ) ?;
168
+ set_headers
169
+ . set ( name. as_str ( ) , & val)
170
+ . map_err ( js_error)
171
+ . with_context ( || format ! ( "could not apply request header: '{name}': '{val}'" ) ) ?;
169
172
}
170
173
request
171
174
} ;
172
175
173
- let resp_value = match fetch_internal ( & request) . await . ok ( ) {
174
- Some ( a) => a,
175
- None => {
176
+ let resp_value = match fetch_internal ( & request) . await {
177
+ Ok ( a) => a,
178
+ Err ( e ) => {
176
179
// If the request failed it may be because of CORS so if a cors proxy
177
180
// is configured then try again with the cors proxy
178
181
let url_store;
179
182
let url = if let Some ( cors_proxy) = cors_proxy {
180
183
url_store = format ! ( "https://{}/{}" , cors_proxy, url) ;
181
184
url_store. as_str ( )
182
185
} else {
183
- // TODO: more descriptive error.
184
- return Err ( anyhow:: anyhow!( "Could not fetch '{url}'" ) ) ;
186
+ return Err ( js_error ( e) . context ( format ! ( "Could not fetch '{url}'" ) ) ) ;
185
187
} ;
186
188
187
189
let request = Request :: new_with_str_and_init ( url, & opts)
188
- . map_err ( |_| anyhow:: anyhow!( "Could not construct request for url '{url}'" ) ) ?;
190
+ . map_err ( js_error)
191
+ . with_context ( || format ! ( "Could not construct request for url '{url}'" ) ) ?;
189
192
190
193
let set_headers = request. headers ( ) ;
191
194
for ( name, val) in headers. iter ( ) {
192
195
let value = String :: from_utf8_lossy ( val. as_bytes ( ) ) ;
193
- set_headers. set ( name. as_str ( ) , & value) . map_err ( |_| {
194
- anyhow:: anyhow!( "Could not apply request header: '{name}': '{value}'" )
195
- } ) ?;
196
+ set_headers
197
+ . set ( name. as_str ( ) , & value)
198
+ . map_err ( js_error)
199
+ . with_context ( || {
200
+ anyhow:: anyhow!( "Could not apply request header: '{name}': '{value}'" )
201
+ } ) ?;
196
202
}
197
203
198
- fetch_internal ( & request) . await . map_err ( |_| {
199
- // TODO: more descriptive error.
200
- anyhow :: anyhow! ( "Could not fetch '{url}'" )
201
- } ) ?
204
+ fetch_internal ( & request)
205
+ . await
206
+ . map_err ( js_error )
207
+ . with_context ( || anyhow :: anyhow! ( "Could not fetch '{url}'" ) ) ?
202
208
}
203
209
} ;
204
210
assert ! ( resp_value. is_instance_of:: <Response >( ) ) ;
@@ -215,6 +221,20 @@ pub async fn fetch(
215
221
Ok ( resp)
216
222
}
217
223
224
+ /// Try to extract the most appropriate error message from a [`JsValue`],
225
+ /// falling back to a generic error message.
226
+ fn js_error ( value : JsValue ) -> anyhow:: Error {
227
+ if let Some ( e) = value. dyn_ref :: < js_sys:: Error > ( ) {
228
+ anyhow:: Error :: msg ( String :: from ( e. message ( ) ) )
229
+ } else if let Some ( obj) = value. dyn_ref :: < js_sys:: Object > ( ) {
230
+ return anyhow:: Error :: msg ( String :: from ( obj. to_string ( ) ) ) ;
231
+ } else if let Some ( s) = value. dyn_ref :: < js_sys:: JsString > ( ) {
232
+ return anyhow:: Error :: msg ( String :: from ( s) ) ;
233
+ } else {
234
+ anyhow:: Error :: msg ( "An unknown error occurred" )
235
+ }
236
+ }
237
+
218
238
/*
219
239
pub async fn fetch_data(
220
240
url: &str,
@@ -231,10 +251,10 @@ pub async fn fetch_data(
231
251
pub async fn get_response_data ( resp : Response ) -> Result < Vec < u8 > , anyhow:: Error > {
232
252
let resp = { JsFuture :: from ( resp. array_buffer ( ) . unwrap ( ) ) } ;
233
253
234
- let arrbuff_value = resp. await . map_err ( |_| {
235
- // TODO: forward error message
236
- anyhow :: anyhow! ( "Could not retrieve response body" )
237
- } ) ?;
254
+ let arrbuff_value = resp
255
+ . await
256
+ . map_err ( js_error )
257
+ . with_context ( || format ! ( "Could not retrieve response body" ) ) ?;
238
258
assert ! ( arrbuff_value. is_instance_of:: <js_sys:: ArrayBuffer >( ) ) ;
239
259
//let arrbuff: js_sys::ArrayBuffer = arrbuff_value.dyn_into().unwrap();
240
260
0 commit comments