use js_sys::{Function, Object, Reflect, Uint8Array};
use std::cell::RefCell;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
struct NodeFs {
read_file_sync: Function,
write_file_sync: Function,
mkdir_sync: Function,
unlink_sync: Function,
}
thread_local! {
static NODE_FS: RefCell<Option<NodeFs>> = const { RefCell::new(None) };
}
#[wasm_bindgen(js_name = __dig_set_node_fs)]
pub fn set_node_fs(fs: &JsValue) {
let method = |name: &str| -> Option<Function> {
Reflect::get(fs, &JsValue::from_str(name))
.ok()
.and_then(|v| v.dyn_into::<Function>().ok())
};
if let (Some(read_file_sync), Some(write_file_sync), Some(mkdir_sync), Some(unlink_sync)) = (
method("readFileSync"),
method("writeFileSync"),
method("mkdirSync"),
method("unlinkSync"),
) {
NODE_FS.with(|slot| {
*slot.borrow_mut() = Some(NodeFs {
read_file_sync,
write_file_sync,
mkdir_sync,
unlink_sync,
});
});
}
}
pub fn is_available() -> bool {
NODE_FS.with(|slot| slot.borrow().is_some())
}
pub fn mkdir_all(dir: &str) {
NODE_FS.with(|slot| {
if let Some(fs) = slot.borrow().as_ref() {
let opts = Object::new();
let _ = Reflect::set(&opts, &JsValue::from_str("recursive"), &JsValue::TRUE);
let _ = fs
.mkdir_sync
.call2(&JsValue::NULL, &JsValue::from_str(dir), &opts);
}
});
}
pub fn read_file(path: &str) -> Option<Vec<u8>> {
NODE_FS.with(|slot| {
let borrow = slot.borrow();
let fs = borrow.as_ref()?;
let buffer = fs
.read_file_sync
.call1(&JsValue::NULL, &JsValue::from_str(path))
.ok()?;
buffer.dyn_into::<Uint8Array>().ok().map(|arr| arr.to_vec())
})
}
pub fn write_file(path: &str, bytes: &[u8]) {
NODE_FS.with(|slot| {
if let Some(fs) = slot.borrow().as_ref() {
let data = Uint8Array::from(bytes);
let _ = fs
.write_file_sync
.call2(&JsValue::NULL, &JsValue::from_str(path), &data);
}
});
}
pub fn remove_file(path: &str) {
NODE_FS.with(|slot| {
if let Some(fs) = slot.borrow().as_ref() {
let _ = fs
.unlink_sync
.call1(&JsValue::NULL, &JsValue::from_str(path));
}
});
}