use redb::TableDefinition;
use rong::*;
mod storage;
pub use storage::*;
pub(crate) const STORAGE_TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("storage");
const REDB_INIT_OVERHEAD: usize = (1.5 * 1024.0 * 1024.0) as usize; pub(crate) const DEFAULT_MAX_TOTAL_SIZE: usize = 20 * 1024 * 1024; pub(crate) const DEFAULT_MAX_USER_DATA_SIZE: usize = DEFAULT_MAX_TOTAL_SIZE + REDB_INIT_OVERHEAD;
pub(crate) const DEFAULT_MAX_KEY_SIZE: usize = 1024; pub(crate) const DEFAULT_MAX_VALUE_SIZE: usize = 5 * 1024 * 1024;
#[derive(IntoJSObj)]
pub struct StorageInfo {
#[rename = "currentSize"]
pub(crate) current_size: u32,
#[rename = "limitSize"]
pub(crate) limit_size: u32,
#[rename = "keyCount"]
pub(crate) key_count: u32,
}
pub fn init(ctx: &JSContext) -> JSResult<()> {
ctx.register_class::<Storage>()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use rong_test::*;
use std::env;
fn workspace_root() -> std::path::PathBuf {
env::current_dir()
.expect("cwd")
.parent()
.and_then(|p| p.parent())
.expect("workspace root")
.to_path_buf()
}
#[test]
fn test_storage() {
async_run!(|ctx: JSContext| async move {
let root = workspace_root();
let storage_path = format!("{}/target/test-tmp/test_storage.db", root.display());
ctx.global().set("TEST_STORAGE_DB_PATH", storage_path)?;
rong_assert::init(&ctx)?;
rong_console::init(&ctx)?;
init(&ctx)?;
let passed = UnitJSRunner::load_script(&ctx, "storage.js")
.await?
.run()
.await?;
assert!(passed);
Ok(())
});
}
#[test]
fn test_storage_injected() {
async_run!(|ctx: JSContext| async move {
let root = workspace_root();
let db_path = root.join("target/test-tmp/test_storage_injected.db");
rong_assert::init(&ctx)?;
rong_console::init(&ctx)?;
init(&ctx)?;
let storage = Storage::new(
db_path,
StorageOptions {
max_data_size: Some(10 * 1024 * 1024),
..Default::default()
},
)?;
let js_storage = Class::lookup::<Storage>(&ctx)?.instance(storage);
ctx.global().set("storage", js_storage)?;
let passed = UnitJSRunner::load_script(&ctx, "storage_injected.js")
.await?
.run()
.await?;
assert!(passed);
Ok(())
});
}
#[test]
fn rust_open_api_provides_handles() {
let root = workspace_root();
let default_path = root.join("target/test-tmp/rust_storage_default.db");
Storage::new(default_path, StorageOptions::default()).expect("default open should succeed");
let custom_path = root.join("target/test-tmp/rust_storage_custom.db");
let options = StorageOptions {
max_key_size: Some(16),
..Default::default()
};
Storage::new(custom_path, options).expect("custom open should succeed");
}
#[test]
fn close_allows_reopen_same_path() {
let root = workspace_root();
let path = root.join("target/test-tmp/rust_storage_reopen.db");
let storage =
Storage::new(&path, StorageOptions::default()).expect("initial open should succeed");
storage.close();
let _storage2 = Storage::new(&path, StorageOptions::default())
.expect("reopen after close should succeed without lock error");
}
}