diff --git a/extensions/webstorage/01_webstorage.js b/extensions/webstorage/01_webstorage.js index a11d44068a..43a1dbbfb6 100644 --- a/extensions/webstorage/01_webstorage.js +++ b/extensions/webstorage/01_webstorage.js @@ -1,11 +1,13 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + ((window) => { const core = window.Deno.core; const webidl = window.__bootstrap.webidl; - const _rid = Symbol("[[rid]]"); + const _persistent = Symbol("[[persistent]]"); class Storage { - [_rid]; + [_persistent]; constructor() { webidl.illegalConstructor(); @@ -13,7 +15,7 @@ get length() { webidl.assertBranded(this, Storage); - return core.opSync("op_webstorage_length", this[_rid]); + return core.opSync("op_webstorage_length", this[_persistent]); } key(index) { @@ -25,10 +27,7 @@ context: "Argument 1", }); - return core.opSync("op_webstorage_key", { - rid: this[_rid], - index, - }); + return core.opSync("op_webstorage_key", index, this[_persistent]); } setItem(key, value) { @@ -45,10 +44,9 @@ }); core.opSync("op_webstorage_set", { - rid: this[_rid], keyName: key, keyValue: value, - }); + }, this[_persistent]); } getItem(key) { @@ -60,10 +58,7 @@ context: "Argument 1", }); - return core.opSync("op_webstorage_get", { - rid: this[_rid], - keyName: key, - }); + return core.opSync("op_webstorage_get", key, this[_persistent]); } removeItem(key) { @@ -75,25 +70,20 @@ context: "Argument 1", }); - core.opSync("op_webstorage_remove", { - rid: this[_rid], - keyName: key, - }); + core.opSync("op_webstorage_remove", key, this[_persistent]); } clear() { webidl.assertBranded(this, Storage); - core.opSync("op_webstorage_clear", this[_rid]); + core.opSync("op_webstorage_clear", this[_persistent]); } } function createStorage(persistent) { if (persistent) window.location; - const rid = core.opSync("op_webstorage_open", persistent); - const storage = webidl.createBranded(Storage); - storage[_rid] = rid; + storage[_persistent] = persistent; const proxy = new Proxy(storage, { deleteProperty(target, key) { @@ -135,7 +125,7 @@ return (typeof target.getItem(p)) === "string"; }, ownKeys() { - return core.opSync("op_webstorage_iterate_keys", rid); + return core.opSync("op_webstorage_iterate_keys", persistent); }, getOwnPropertyDescriptor(target, key) { if (arguments.length === 1) { diff --git a/extensions/webstorage/Cargo.toml b/extensions/webstorage/Cargo.toml index ab0a6299e9..506014b170 100644 --- a/extensions/webstorage/Cargo.toml +++ b/extensions/webstorage/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. [package] name = "deno_webstorage" diff --git a/extensions/webstorage/lib.rs b/extensions/webstorage/lib.rs index 90ae0598ad..8b3e206fba 100644 --- a/extensions/webstorage/lib.rs +++ b/extensions/webstorage/lib.rs @@ -1,18 +1,14 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::bad_resource_id; use deno_core::error::AnyError; use deno_core::include_js_files; use deno_core::op_sync; use deno_core::Extension; use deno_core::OpState; -use deno_core::Resource; -use deno_core::ZeroCopyBuf; use rusqlite::params; use rusqlite::Connection; use rusqlite::OptionalExtension; use serde::Deserialize; -use std::borrow::Cow; use std::fmt; use std::path::PathBuf; @@ -26,7 +22,6 @@ pub fn init(location_data_dir: Option) -> Extension { "01_webstorage.js", )) .ops(vec![ - ("op_webstorage_open", op_sync(op_webstorage_open)), ("op_webstorage_length", op_sync(op_webstorage_length)), ("op_webstorage_key", op_sync(op_webstorage_key)), ("op_webstorage_set", op_sync(op_webstorage_set)), @@ -51,82 +46,73 @@ pub fn get_declaration() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_webstorage.d.ts") } -struct WebStorageConnectionResource(Connection); +struct LocalStorage(Connection); +struct SessionStorage(Connection); -impl Resource for WebStorageConnectionResource { - fn name(&self) -> Cow { - "webStorage".into() - } -} - -pub fn op_webstorage_open( +fn get_webstorage( state: &mut OpState, persistent: bool, - _zero_copy: Option, -) -> Result { - let connection = if persistent { - let path = state.try_borrow::().ok_or_else(|| { - DomExceptionNotSupportedError::new( - "LocalStorage is not supported in this context.", - ) - })?; - std::fs::create_dir_all(&path.0)?; - Connection::open(path.0.join("local_storage"))? +) -> Result<&Connection, AnyError> { + let conn = if persistent { + if state.try_borrow::().is_none() { + let path = state.try_borrow::().ok_or_else(|| { + DomExceptionNotSupportedError::new( + "LocalStorage is not supported in this context.", + ) + })?; + std::fs::create_dir_all(&path.0)?; + let conn = Connection::open(path.0.join("local_storage"))?; + conn.execute( + "CREATE TABLE IF NOT EXISTS data (key VARCHAR UNIQUE, value VARCHAR)", + params![], + )?; + + state.put(LocalStorage(conn)); + } + + &state.borrow::().0 } else { - Connection::open_in_memory()? + if state.try_borrow::().is_none() { + let conn = Connection::open_in_memory()?; + conn.execute( + "CREATE TABLE data (key VARCHAR UNIQUE, value VARCHAR)", + params![], + )?; + + state.put(SessionStorage(conn)); + } + + &state.borrow::().0 }; - connection.execute( - "CREATE TABLE IF NOT EXISTS data (key VARCHAR UNIQUE, value VARCHAR)", - params![], - )?; - - let rid = state - .resource_table - .add(WebStorageConnectionResource(connection)); - Ok(rid) + Ok(conn) } pub fn op_webstorage_length( state: &mut OpState, - rid: u32, - _zero_copy: Option, + persistent: bool, + _: (), ) -> Result { - let resource = state - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - let mut stmt = resource.0.prepare("SELECT COUNT(*) FROM data")?; + let mut stmt = conn.prepare("SELECT COUNT(*) FROM data")?; let length: u32 = stmt.query_row(params![], |row| row.get(0))?; Ok(length) } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct KeyArgs { - rid: u32, - index: u32, -} - pub fn op_webstorage_key( state: &mut OpState, - args: KeyArgs, - _zero_copy: Option, + index: u32, + persistent: bool, ) -> Result, AnyError> { - let resource = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - let mut stmt = resource - .0 - .prepare("SELECT key FROM data LIMIT 1 OFFSET ?")?; + let mut stmt = conn.prepare("SELECT key FROM data LIMIT 1 OFFSET ?")?; let key: Option = stmt - .query_row(params![args.index], |row| row.get(0)) + .query_row(params![index], |row| row.get(0)) .optional()?; Ok(key) @@ -135,7 +121,6 @@ pub fn op_webstorage_key( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct SetArgs { - rid: u32, key_name: String, key_value: String, } @@ -143,16 +128,12 @@ pub struct SetArgs { pub fn op_webstorage_set( state: &mut OpState, args: SetArgs, - _zero_copy: Option, + persistent: bool, ) -> Result<(), AnyError> { - let resource = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - let mut stmt = resource - .0 - .prepare("SELECT SUM(pgsize) FROM dbstat WHERE name = 'data'")?; + let mut stmt = + conn.prepare("SELECT SUM(pgsize) FROM dbstat WHERE name = 'data'")?; let size: u32 = stmt.query_row(params![], |row| row.get(0))?; if size >= 5000000 { @@ -162,7 +143,7 @@ pub fn op_webstorage_set( ); } - resource.0.execute( + conn.execute( "INSERT OR REPLACE INTO data (key, value) VALUES (?, ?)", params![args.key_name, args.key_value], )?; @@ -170,68 +151,43 @@ pub fn op_webstorage_set( Ok(()) } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GetArgs { - rid: u32, - key_name: String, -} - pub fn op_webstorage_get( state: &mut OpState, - args: GetArgs, - _zero_copy: Option, + key_name: String, + persistent: bool, ) -> Result, AnyError> { - let resource = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - let mut stmt = resource.0.prepare("SELECT value FROM data WHERE key = ?")?; + let mut stmt = conn.prepare("SELECT value FROM data WHERE key = ?")?; let val = stmt - .query_row(params![args.key_name], |row| row.get(0)) + .query_row(params![key_name], |row| row.get(0)) .optional()?; Ok(val) } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RemoveArgs { - rid: u32, - key_name: String, -} - pub fn op_webstorage_remove( state: &mut OpState, - args: RemoveArgs, - _zero_copy: Option, + key_name: String, + persistent: bool, ) -> Result<(), AnyError> { - let resource = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - resource - .0 - .execute("DELETE FROM data WHERE key = ?", params![args.key_name])?; + conn.execute("DELETE FROM data WHERE key = ?", params![key_name])?; Ok(()) } pub fn op_webstorage_clear( state: &mut OpState, - rid: u32, - _zero_copy: Option, + persistent: bool, + _: (), ) -> Result<(), AnyError> { - let resource = state - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - resource.0.execute("DROP TABLE data", params![])?; - resource.0.execute( + conn.execute("DROP TABLE data", params![])?; + conn.execute( "CREATE TABLE data (key VARCHAR UNIQUE, value VARCHAR)", params![], )?; @@ -241,15 +197,12 @@ pub fn op_webstorage_clear( pub fn op_webstorage_iterate_keys( state: &mut OpState, - rid: u32, - _zero_copy: Option, + persistent: bool, + _: (), ) -> Result, AnyError> { - let resource = state - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; + let conn = get_webstorage(state, persistent)?; - let mut stmt = resource.0.prepare("SELECT key FROM data")?; + let mut stmt = conn.prepare("SELECT key FROM data")?; let keys = stmt .query_map(params![], |row| row.get::<_, String>(0))?