use crate::cdp::session::CdpSession;
use crate::error::{Error, Result};
use serde_json::{json, Value};
use std::sync::Arc;
#[derive(Clone)]
pub struct WebStorage {
inner: Arc<WebStorageInner>,
}
struct WebStorageInner {
session: CdpSession,
security_origin: String,
is_local_storage: bool,
}
impl WebStorage {
pub(crate) fn new(session: CdpSession, security_origin: String, is_local_storage: bool) -> Self {
Self {
inner: Arc::new(WebStorageInner {
session,
security_origin,
is_local_storage,
}),
}
}
pub(crate) fn local_storage(session: CdpSession, security_origin: String) -> Self {
Self::new(session, security_origin, true)
}
pub(crate) fn session_storage(session: CdpSession, security_origin: String) -> Self {
Self::new(session, security_origin, false)
}
fn storage_id(&self) -> Value {
json!({
"securityOrigin": self.inner.security_origin,
"isLocalStorage": self.inner.is_local_storage,
})
}
async fn items(&self) -> Result<Vec<(String, String)>> {
let resp: Value = self
.inner
.session
.send(
"DOMStorage.getDOMStorageItems",
json!({ "storageId": self.storage_id() }),
)
.await?;
let arr = resp
.get("entries")
.and_then(|v| v.as_array())
.ok_or_else(|| Error::ProtocolError("getDOMStorageItems missing 'entries'".into()))?;
let mut out = Vec::with_capacity(arr.len());
for entry in arr {
let mut it = entry.as_array().into_iter().flatten();
let key = it
.next()
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let value = it
.next()
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
out.push((key, value));
}
Ok(out)
}
pub async fn get(&self, key: &str) -> Result<Option<String>> {
let items = self.items().await?;
Ok(items
.into_iter()
.find_map(|(k, v)| if k == key { Some(v) } else { None }))
}
pub async fn set(&self, key: &str, value: &str) -> Result<()> {
self.inner
.session
.send(
"DOMStorage.setDOMStorageItem",
json!({
"storageId": self.storage_id(),
"key": key,
"value": value,
}),
)
.await?;
Ok(())
}
pub async fn remove(&self, key: &str) -> Result<()> {
self.inner
.session
.send(
"DOMStorage.removeDOMStorageItem",
json!({
"storageId": self.storage_id(),
"key": key,
}),
)
.await?;
Ok(())
}
pub async fn clear(&self) -> Result<()> {
self.inner
.session
.send(
"DOMStorage.clear",
json!({ "storageId": self.storage_id() }),
)
.await?;
Ok(())
}
pub async fn keys(&self) -> Result<Vec<String>> {
Ok(self.items().await?.into_iter().map(|(k, _)| k).collect())
}
pub async fn size(&self) -> Result<usize> {
Ok(self.items().await?.len())
}
pub async fn has(&self, key: &str) -> Result<bool> {
Ok(self.items().await?.iter().any(|(k, _)| k == key))
}
pub fn security_origin(&self) -> &str {
&self.inner.security_origin
}
pub fn is_local_storage(&self) -> bool {
self.inner.is_local_storage
}
}