persist cookies immediately

pull/1978/head
Lucas Nogueira 4 months ago
parent ea860c47c0
commit 356b7ece49
No known key found for this signature in database
GPG Key ID: A05EE2227C581CD7

@ -266,7 +266,7 @@ pub async fn fetch<R: Runtime>(
#[cfg(feature = "cookies")]
{
builder = builder.cookie_provider(state.cookies_jar.clone());
builder = builder.cookie_provider(Arc::new(state.cookies_jar));
}
let mut request = builder.build()?.request(method.clone(), url);

@ -4,8 +4,6 @@
//! Access the HTTP client written in Rust.
use std::io::Cursor;
pub use reqwest;
use tauri::{
plugin::{Builder, TauriPlugin},
@ -22,20 +20,17 @@ mod scope;
pub(crate) struct Http {
#[cfg(feature = "cookies")]
cookies_jar_path: std::path::PathBuf,
#[cfg(feature = "cookies")]
cookies_jar: std::sync::Arc<crate::reqwest_cookie_store::CookieStoreMutex>,
cookies_jar: crate::reqwest_cookie_store::CookieStoreMutex,
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::<R>::new("http")
.setup(|app, _| {
#[cfg(feature = "cookies")]
let (cookies_jar_path, cookies_jar) = {
let cookies_jar = {
use crate::reqwest_cookie_store::*;
use std::fs::File;
use std::io::BufReader;
use std::sync::Arc;
let cache_dir = app.path().app_cache_dir()?;
std::fs::create_dir_all(&cache_dir)?;
@ -48,22 +43,18 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.open(&path)?;
let reader = BufReader::new(file);
let store = CookieStoreMutex::load(reader)
.or_else(|_e| {
#[cfg(feature = "tracing")]
tracing::warn!(
"failed to load cookie store: {_e}, falling back to empty store"
);
CookieStoreMutex::load(Cursor::new("[]".to_string()))
})
.map_err(|e| e.to_string())?;
(path, Arc::new(store))
let store = CookieStoreMutex::load(path.clone(), reader).unwrap_or_else(|_e| {
#[cfg(feature = "tracing")]
tracing::warn!(
"failed to load cookie store: {_e}, falling back to empty store"
);
CookieStoreMutex::new(path, Default::default())
});
store
};
let state = Http {
#[cfg(feature = "cookies")]
cookies_jar_path,
#[cfg(feature = "cookies")]
cookies_jar,
};
@ -75,14 +66,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.on_event(|app, event| {
#[cfg(feature = "cookies")]
if let tauri::RunEvent::Exit = event {
use std::fs::File;
use std::io::BufWriter;
let state = app.state::<Http>();
if let Ok(file) = File::create(&state.cookies_jar_path) {
let mut writer = BufWriter::new(file);
let _ = state.cookies_jar.save(&mut writer);
if let Err(_e) = state.cookies_jar.save() {
#[cfg(feature = "tracing")]
tracing::error!("failed to save cookie jar: {_e}");
}
}
})

@ -4,7 +4,12 @@
// taken from https://github.com/pfernie/reqwest_cookie_store/blob/2ec4afabcd55e24d3afe3f0626ee6dc97bed938d/src/lib.rs
use std::sync::{Mutex, MutexGuard, PoisonError};
use std::{
fs::File,
io::BufWriter,
path::PathBuf,
sync::{Arc, Mutex, MutexGuard, PoisonError},
};
use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
use reqwest::header::HeaderValue;
@ -41,47 +46,61 @@ fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> {
/// A [`cookie_store::CookieStore`] wrapped internally by a [`std::sync::Mutex`], suitable for use in
/// async/concurrent contexts.
#[derive(Debug, Serialize, Deserialize)]
pub struct CookieStoreMutex(Mutex<CookieStore>);
impl Default for CookieStoreMutex {
/// Create a new, empty [`CookieStoreMutex`]
fn default() -> Self {
CookieStoreMutex::new(CookieStore::default())
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookieStoreMutex {
pub path: PathBuf,
store: Arc<Mutex<CookieStore>>,
}
impl CookieStoreMutex {
/// Create a new [`CookieStoreMutex`] from an existing [`cookie_store::CookieStore`].
pub const fn new(cookie_store: CookieStore) -> CookieStoreMutex {
CookieStoreMutex(Mutex::new(cookie_store))
pub fn new(path: PathBuf, cookie_store: CookieStore) -> CookieStoreMutex {
CookieStoreMutex {
path,
store: Arc::new(Mutex::new(cookie_store)),
}
}
/// Lock and get a handle to the contained [`cookie_store::CookieStore`].
pub fn lock(
&self,
) -> Result<MutexGuard<'_, CookieStore>, PoisonError<MutexGuard<'_, CookieStore>>> {
self.0.lock()
self.store.lock()
}
pub fn load<R: std::io::BufRead>(reader: R) -> cookie_store::Result<CookieStoreMutex> {
cookie_store::serde::load(reader, |c| serde_json::from_str(c)).map(CookieStoreMutex::new)
pub fn load<R: std::io::BufRead>(
path: PathBuf,
reader: R,
) -> cookie_store::Result<CookieStoreMutex> {
cookie_store::serde::load(reader, |c| serde_json::from_str(c))
.map(|store| CookieStoreMutex::new(path, store))
}
pub fn save<W: std::io::Write>(&self, writer: &mut W) -> cookie_store::Result<()> {
pub fn save(&self) -> cookie_store::Result<()> {
let file = File::create(&self.path)?;
let mut writer = BufWriter::new(file);
let store = self.lock().expect("poisoned cookie jar mutex");
cookie_store::serde::save(&store, writer, serde_json::to_string)
cookie_store::serde::save(&store, &mut writer, serde_json::to_string)
}
}
impl reqwest::cookie::CookieStore for CookieStoreMutex {
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
let mut store = self.0.lock().unwrap();
let mut store = self.store.lock().unwrap();
set_cookies(&mut store, cookie_headers, url);
// try to persist cookies immediately asynchronously
let cookies_jar = self.clone();
tauri::async_runtime::spawn(async move {
if let Err(_e) = cookies_jar.save() {
#[cfg(feature = "tracing")]
tracing::error!("failed to save cookie jar: {_e}");
}
});
}
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
let store = self.0.lock().unwrap();
let store = self.store.lock().unwrap();
cookies(&store, url)
}
}

Loading…
Cancel
Save