mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
fix(webstorage): use opstate for sqlite connection (#10692)
Fixes #10691
This commit is contained in:
parent
91decbfabf
commit
1cb5ec3c5e
3 changed files with 80 additions and 137 deletions
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<PathBuf>) -> 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<str> {
|
||||
"webStorage".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn op_webstorage_open(
|
||||
fn get_webstorage(
|
||||
state: &mut OpState,
|
||||
persistent: bool,
|
||||
_zero_copy: Option<ZeroCopyBuf>,
|
||||
) -> Result<u32, AnyError> {
|
||||
let connection = if persistent {
|
||||
let path = state.try_borrow::<LocationDataDir>().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::<LocalStorage>().is_none() {
|
||||
let path = state.try_borrow::<LocationDataDir>().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::<LocalStorage>().0
|
||||
} else {
|
||||
Connection::open_in_memory()?
|
||||
if state.try_borrow::<SessionStorage>().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::<SessionStorage>().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<ZeroCopyBuf>,
|
||||
persistent: bool,
|
||||
_: (),
|
||||
) -> Result<u32, AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<ZeroCopyBuf>,
|
||||
index: u32,
|
||||
persistent: bool,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<String> = 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<ZeroCopyBuf>,
|
||||
persistent: bool,
|
||||
) -> Result<(), AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<ZeroCopyBuf>,
|
||||
key_name: String,
|
||||
persistent: bool,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<ZeroCopyBuf>,
|
||||
key_name: String,
|
||||
persistent: bool,
|
||||
) -> Result<(), AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<ZeroCopyBuf>,
|
||||
persistent: bool,
|
||||
_: (),
|
||||
) -> Result<(), AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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<ZeroCopyBuf>,
|
||||
persistent: bool,
|
||||
_: (),
|
||||
) -> Result<Vec<String>, AnyError> {
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<WebStorageConnectionResource>(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))?
|
||||
|
|
Loading…
Reference in a new issue