Skip to content

Commit

Permalink
[fix] handle worker context
Browse files Browse the repository at this point in the history
  • Loading branch information
ca333 committed Aug 24, 2023
1 parent 410eda2 commit ae4a809
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 15 deletions.
61 changes: 55 additions & 6 deletions mm2src/mm2_db/src/indexed_db/drivers/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use mm2_err_handle::prelude::*;
use std::collections::{HashMap, HashSet};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{IdbDatabase, IdbOpenDbRequest, IdbTransaction, IdbVersionChangeEvent};
use web_sys::{IdbDatabase, IdbOpenDbRequest, IdbFactory, IdbTransaction, IdbVersionChangeEvent, Window, WorkerGlobalScope};

pub type InitDbResult<T> = Result<T, MmError<InitDbError>>;

Expand Down Expand Up @@ -73,11 +73,60 @@ impl IdbDatabaseBuilder {
let (table_names, on_upgrade_needed_handlers) = Self::tables_into_parts(self.tables)?;
info!("Open '{}' database with tables: {:?}", self.db_name, table_names);

let window = web_sys::window().expect("!window");
let indexed_db = match window.indexed_db() {
Ok(Some(db)) => db,
Ok(None) => return MmError::err(InitDbError::NotSupported("Unknown error".to_owned())),
Err(e) => return MmError::err(InitDbError::NotSupported(stringify_js_error(&e))),
// get global context
let global = js_sys::global();
//
// // check if dyn casting to window type was successful
// let indexed_db_factory: Option<IdbFactory> = if global.dyn_ref::<Window>().is_some() {
// global.dyn_ref::<Window>().unwrap().indexed_db().unwrap_or(None)
// // check if worker context
// } else if global.dyn_ref::<WorkerGlobalScope>().is_some() {
// global.dyn_ref::<WorkerGlobalScope>().unwrap().indexed_db().unwrap_or(None)
// } else {
// None
// };
// // bind value based on pattern matching against idbfactory
// let indexed_db = match indexed_db_factory {
// Ok(Some(db)) => db,
// // err handling
// Ok(None) => {
// if global.dyn_ref::<Window>().is_some() {
// return MmError::err(InitDbError::NotSupported("IndexedDB not supported in window context".to_owned()));
// } else if global.dyn_ref::<WorkerGlobalScope>().is_some() {
// return MmError::err(InitDbError::NotSupported("IndexedDB not supported in worker context".to_owned()));
// } else {
// return MmError::err(InitDbError::UnexpectedState("rekt".to_owned()));
// }
// },
// Err(e) => return MmError::err(InitDbError::NotSupported(stringify_js_error(&e)))
// };

// Using Result here (L111 - "cast check") for more precise error handling and messaging.
// However, for performance and memory considerations, it might be worth evaluating the use of Option (as seen in commented-out code above).
// Option<T> might have a slight edge in terms of memory consumption, especially if the error type E in Result<T, E> is large and/or complex.
// Moreover, in micro-benchmarks, Option<T> seems to demonstrate marginal performance advantages.
// But these trade-offs were considered acceptable for the benefit of clearer error states in this context.
// Ref: https://users.rust-lang.org/t/performance-impact-of-result-vs-option/17783, etc.

let indexed_db_result: Result<IdbFactory, InitDbError> = if let Some(window) = global.dyn_ref::<Window>() {
match window.indexed_db() {
Ok(Some(db)) => Ok(db),
Ok(None) => Err(InitDbError::NotSupported("IndexedDB not supported in window context".to_owned())),
Err(e) => Err(InitDbError::NotSupported(stringify_js_error(&e))),
}
} else if global.dyn_ref::<WorkerGlobalScope>().is_some() {
match global.dyn_ref::<WorkerGlobalScope>().unwrap().indexed_db() {
Ok(Some(db)) => Ok(db),
Ok(None) => Err(InitDbError::NotSupported("IndexedDB not supported in worker context".to_owned())),
Err(e) => Err(InitDbError::NotSupported(stringify_js_error(&e))),
}
} else {
Err(InitDbError::UnexpectedState("Unknown context".to_owned()))
};

let indexed_db = match indexed_db_result {
Ok(db) => db,
Err(e) => return MmError::err(e),
};

let db_request = match indexed_db.open_with_u32(&self.db_name, self.db_version) {
Expand Down
25 changes: 16 additions & 9 deletions mm2src/mm2_net/src/wasm_http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,17 @@ impl FetchRequest {
}

async fn fetch(request: Self) -> FetchResult<JsResponse> {
let window = web_sys::window().expect("!window");
let global = js_sys::global();
let uri = request.uri;

let mut req_init = RequestInit::new();
req_init.method(request.method.as_str());
req_init.body(request.body.map(RequestBody::into_js_value).as_ref());

if let Some(mode) = request.mode {
req_init.mode(mode);
}

let js_request = Request::new_with_str_and_init(&uri, &req_init)
.map_to_mm(|e| SlurpError::Internal(stringify_js_error(&e)))?;
for (hkey, hval) in request.headers {
Expand All @@ -164,22 +164,29 @@ impl FetchRequest {
.set(&hkey, &hval)
.map_to_mm(|e| SlurpError::Internal(stringify_js_error(&e)))?;
}

let request_promise = window.fetch_with_request(&js_request);

let request_promise = match global.dyn_into::<web_sys::Window>() {
Ok(window) => window.fetch_with_request(&js_request),
Err(global) => match global.dyn_into::<web_sys::WorkerGlobalScope>() {
Ok(worker) => worker.fetch_with_request(&js_request),
Err(_) => return Err(SlurpError::Internal("Unknown context: Neither window nor worker.".to_string()).into()),
},
};

let future = JsFuture::from(request_promise);
let resp_value = future.await.map_to_mm(|e| SlurpError::Transport {
uri: uri.clone(),
error: stringify_js_error(&e),
})?;

let js_response: JsResponse = match resp_value.dyn_into() {
Ok(res) => res,
Err(origin_val) => {
let error = format!("Error casting {:?} to 'JsResponse'", origin_val);
return MmError::err(SlurpError::Internal(error));
},
};

let status_code = js_response.status();
let status_code = match StatusCode::from_u16(status_code) {
Ok(code) => code,
Expand All @@ -188,10 +195,10 @@ impl FetchRequest {
return MmError::err(SlurpError::ErrorDeserializing { uri, error });
},
};

Ok((status_code, js_response))
}

/// The private non-Send method that is called in a spawned future.
async fn fetch_str(request: Self) -> FetchResult<String> {
let uri = request.uri.clone();
Expand Down

0 comments on commit ae4a809

Please sign in to comment.