Skip to content

Commit 356b7ec

Browse files
committed
persist cookies immediately
1 parent ea860c4 commit 356b7ec

File tree

3 files changed

+52
-45
lines changed

3 files changed

+52
-45
lines changed

plugins/http/src/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ pub async fn fetch<R: Runtime>(
266266

267267
#[cfg(feature = "cookies")]
268268
{
269-
builder = builder.cookie_provider(state.cookies_jar.clone());
269+
builder = builder.cookie_provider(Arc::new(state.cookies_jar));
270270
}
271271

272272
let mut request = builder.build()?.request(method.clone(), url);

plugins/http/src/lib.rs

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
//! Access the HTTP client written in Rust.
66
7-
use std::io::Cursor;
8-
97
pub use reqwest;
108
use tauri::{
119
plugin::{Builder, TauriPlugin},
@@ -22,20 +20,17 @@ mod scope;
2220

2321
pub(crate) struct Http {
2422
#[cfg(feature = "cookies")]
25-
cookies_jar_path: std::path::PathBuf,
26-
#[cfg(feature = "cookies")]
27-
cookies_jar: std::sync::Arc<crate::reqwest_cookie_store::CookieStoreMutex>,
23+
cookies_jar: crate::reqwest_cookie_store::CookieStoreMutex,
2824
}
2925

3026
pub fn init<R: Runtime>() -> TauriPlugin<R> {
3127
Builder::<R>::new("http")
3228
.setup(|app, _| {
3329
#[cfg(feature = "cookies")]
34-
let (cookies_jar_path, cookies_jar) = {
30+
let cookies_jar = {
3531
use crate::reqwest_cookie_store::*;
3632
use std::fs::File;
3733
use std::io::BufReader;
38-
use std::sync::Arc;
3934

4035
let cache_dir = app.path().app_cache_dir()?;
4136
std::fs::create_dir_all(&cache_dir)?;
@@ -48,22 +43,18 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
4843
.open(&path)?;
4944

5045
let reader = BufReader::new(file);
51-
let store = CookieStoreMutex::load(reader)
52-
.or_else(|_e| {
53-
#[cfg(feature = "tracing")]
54-
tracing::warn!(
55-
"failed to load cookie store: {_e}, falling back to empty store"
56-
);
57-
CookieStoreMutex::load(Cursor::new("[]".to_string()))
58-
})
59-
.map_err(|e| e.to_string())?;
60-
61-
(path, Arc::new(store))
46+
let store = CookieStoreMutex::load(path.clone(), reader).unwrap_or_else(|_e| {
47+
#[cfg(feature = "tracing")]
48+
tracing::warn!(
49+
"failed to load cookie store: {_e}, falling back to empty store"
50+
);
51+
CookieStoreMutex::new(path, Default::default())
52+
});
53+
54+
store
6255
};
6356

6457
let state = Http {
65-
#[cfg(feature = "cookies")]
66-
cookies_jar_path,
6758
#[cfg(feature = "cookies")]
6859
cookies_jar,
6960
};
@@ -75,14 +66,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
7566
.on_event(|app, event| {
7667
#[cfg(feature = "cookies")]
7768
if let tauri::RunEvent::Exit = event {
78-
use std::fs::File;
79-
use std::io::BufWriter;
80-
8169
let state = app.state::<Http>();
8270

83-
if let Ok(file) = File::create(&state.cookies_jar_path) {
84-
let mut writer = BufWriter::new(file);
85-
let _ = state.cookies_jar.save(&mut writer);
71+
if let Err(_e) = state.cookies_jar.save() {
72+
#[cfg(feature = "tracing")]
73+
tracing::error!("failed to save cookie jar: {_e}");
8674
}
8775
}
8876
})

plugins/http/src/reqwest_cookie_store.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
// taken from https://github.com/pfernie/reqwest_cookie_store/blob/2ec4afabcd55e24d3afe3f0626ee6dc97bed938d/src/lib.rs
66

7-
use std::sync::{Mutex, MutexGuard, PoisonError};
7+
use std::{
8+
fs::File,
9+
io::BufWriter,
10+
path::PathBuf,
11+
sync::{Arc, Mutex, MutexGuard, PoisonError},
12+
};
813

914
use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
1015
use reqwest::header::HeaderValue;
@@ -41,47 +46,61 @@ fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> {
4146

4247
/// A [`cookie_store::CookieStore`] wrapped internally by a [`std::sync::Mutex`], suitable for use in
4348
/// async/concurrent contexts.
44-
#[derive(Debug, Serialize, Deserialize)]
45-
pub struct CookieStoreMutex(Mutex<CookieStore>);
46-
47-
impl Default for CookieStoreMutex {
48-
/// Create a new, empty [`CookieStoreMutex`]
49-
fn default() -> Self {
50-
CookieStoreMutex::new(CookieStore::default())
51-
}
49+
#[derive(Debug, Clone, Serialize, Deserialize)]
50+
pub struct CookieStoreMutex {
51+
pub path: PathBuf,
52+
store: Arc<Mutex<CookieStore>>,
5253
}
5354

5455
impl CookieStoreMutex {
5556
/// Create a new [`CookieStoreMutex`] from an existing [`cookie_store::CookieStore`].
56-
pub const fn new(cookie_store: CookieStore) -> CookieStoreMutex {
57-
CookieStoreMutex(Mutex::new(cookie_store))
57+
pub fn new(path: PathBuf, cookie_store: CookieStore) -> CookieStoreMutex {
58+
CookieStoreMutex {
59+
path,
60+
store: Arc::new(Mutex::new(cookie_store)),
61+
}
5862
}
5963

6064
/// Lock and get a handle to the contained [`cookie_store::CookieStore`].
6165
pub fn lock(
6266
&self,
6367
) -> Result<MutexGuard<'_, CookieStore>, PoisonError<MutexGuard<'_, CookieStore>>> {
64-
self.0.lock()
68+
self.store.lock()
6569
}
6670

67-
pub fn load<R: std::io::BufRead>(reader: R) -> cookie_store::Result<CookieStoreMutex> {
68-
cookie_store::serde::load(reader, |c| serde_json::from_str(c)).map(CookieStoreMutex::new)
71+
pub fn load<R: std::io::BufRead>(
72+
path: PathBuf,
73+
reader: R,
74+
) -> cookie_store::Result<CookieStoreMutex> {
75+
cookie_store::serde::load(reader, |c| serde_json::from_str(c))
76+
.map(|store| CookieStoreMutex::new(path, store))
6977
}
7078

71-
pub fn save<W: std::io::Write>(&self, writer: &mut W) -> cookie_store::Result<()> {
79+
pub fn save(&self) -> cookie_store::Result<()> {
80+
let file = File::create(&self.path)?;
81+
let mut writer = BufWriter::new(file);
7282
let store = self.lock().expect("poisoned cookie jar mutex");
73-
cookie_store::serde::save(&store, writer, serde_json::to_string)
83+
cookie_store::serde::save(&store, &mut writer, serde_json::to_string)
7484
}
7585
}
7686

7787
impl reqwest::cookie::CookieStore for CookieStoreMutex {
7888
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
79-
let mut store = self.0.lock().unwrap();
89+
let mut store = self.store.lock().unwrap();
8090
set_cookies(&mut store, cookie_headers, url);
91+
92+
// try to persist cookies immediately asynchronously
93+
let cookies_jar = self.clone();
94+
tauri::async_runtime::spawn(async move {
95+
if let Err(_e) = cookies_jar.save() {
96+
#[cfg(feature = "tracing")]
97+
tracing::error!("failed to save cookie jar: {_e}");
98+
}
99+
});
81100
}
82101

83102
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
84-
let store = self.0.lock().unwrap();
103+
let store = self.store.lock().unwrap();
85104
cookies(&store, url)
86105
}
87106
}

0 commit comments

Comments
 (0)