55// taken from https://github.com/pfernie/reqwest_cookie_store/blob/2ec4afabcd55e24d3afe3f0626ee6dc97bed938d/src/lib.rs
66
77use std:: {
8- fs:: File ,
9- io:: BufWriter ,
108 path:: PathBuf ,
11- sync:: { Arc , Mutex , MutexGuard , PoisonError } ,
9+ sync:: { mpsc :: Receiver , Mutex } ,
1210} ;
1311
1412use cookie_store:: { CookieStore , RawCookie , RawCookieParseError } ;
1513use reqwest:: header:: HeaderValue ;
16- use serde:: { Deserialize , Serialize } ;
1714
1815fn set_cookies (
1916 cookie_store : & mut CookieStore ,
@@ -46,28 +43,23 @@ fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> {
4643
4744/// A [`cookie_store::CookieStore`] wrapped internally by a [`std::sync::Mutex`], suitable for use in
4845/// async/concurrent contexts.
49- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
46+ #[ derive( Debug ) ]
5047pub struct CookieStoreMutex {
5148 pub path : PathBuf ,
52- store : Arc < Mutex < CookieStore > > ,
49+ store : Mutex < CookieStore > ,
50+ save_task : Mutex < Option < CancellableTask > > ,
5351}
5452
5553impl CookieStoreMutex {
5654 /// Create a new [`CookieStoreMutex`] from an existing [`cookie_store::CookieStore`].
5755 pub fn new ( path : PathBuf , cookie_store : CookieStore ) -> CookieStoreMutex {
5856 CookieStoreMutex {
5957 path,
60- store : Arc :: new ( Mutex :: new ( cookie_store) ) ,
58+ store : Mutex :: new ( cookie_store) ,
59+ save_task : Default :: default ( ) ,
6160 }
6261 }
6362
64- /// Lock and get a handle to the contained [`cookie_store::CookieStore`].
65- pub fn lock (
66- & self ,
67- ) -> Result < MutexGuard < ' _ , CookieStore > , PoisonError < MutexGuard < ' _ , CookieStore > > > {
68- self . store . lock ( )
69- }
70-
7163 pub fn load < R : std:: io:: BufRead > (
7264 path : PathBuf ,
7365 reader : R ,
@@ -76,31 +68,66 @@ impl CookieStoreMutex {
7668 . map ( |store| CookieStoreMutex :: new ( path, store) )
7769 }
7870
79- pub fn save ( & self ) -> cookie_store:: Result < ( ) > {
80- let file = File :: create ( & self . path ) ?;
81- let mut writer = BufWriter :: new ( file) ;
82- let store = self . lock ( ) . expect ( "poisoned cookie jar mutex" ) ;
83- cookie_store:: serde:: save ( & store, & mut writer, serde_json:: to_string)
71+ fn cookies_to_str ( & self ) -> Result < String , serde_json:: Error > {
72+ let mut cookies = Vec :: new ( ) ;
73+ for cookie in self
74+ . store
75+ . lock ( )
76+ . expect ( "poisoned cookie jar mutex" )
77+ . iter_unexpired ( )
78+ {
79+ if cookie. is_persistent ( ) {
80+ cookies. push ( cookie. clone ( ) ) ;
81+ }
82+ }
83+ serde_json:: to_string ( & cookies)
84+ }
85+
86+ pub fn request_save ( & self ) -> cookie_store:: Result < Receiver < ( ) > > {
87+ let cookie_str = self . cookies_to_str ( ) ?;
88+ let path = self . path . clone ( ) ;
89+ let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
90+ let task = tauri:: async_runtime:: spawn ( async move {
91+ match tokio:: fs:: write ( & path, & cookie_str) . await {
92+ Ok ( ( ) ) => {
93+ let _ = tx. send ( ( ) ) ;
94+ }
95+ Err ( _e) => {
96+ #[ cfg( feature = "tracing" ) ]
97+ tracing:: error!( "failed to save cookie jar: {_e}" ) ;
98+ }
99+ }
100+ } ) ;
101+ self . save_task
102+ . lock ( )
103+ . unwrap ( )
104+ . replace ( CancellableTask ( task) ) ;
105+ Ok ( rx)
84106 }
85107}
86108
87109impl reqwest:: cookie:: CookieStore for CookieStoreMutex {
88110 fn set_cookies ( & self , cookie_headers : & mut dyn Iterator < Item = & HeaderValue > , url : & url:: Url ) {
89- let mut store = self . store . lock ( ) . unwrap ( ) ;
90- set_cookies ( & mut store, cookie_headers, url) ;
111+ set_cookies ( & mut self . store . lock ( ) . unwrap ( ) , cookie_headers, url) ;
91112
92113 // 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- } ) ;
114+ if let Err ( _e) = self . request_save ( ) {
115+ #[ cfg( feature = "tracing" ) ]
116+ tracing:: error!( "failed to save cookie jar: {_e}" ) ;
117+ }
100118 }
101119
102120 fn cookies ( & self , url : & url:: Url ) -> Option < HeaderValue > {
103121 let store = self . store . lock ( ) . unwrap ( ) ;
104122 cookies ( & store, url)
105123 }
106124}
125+
126+ #[ derive( Debug ) ]
127+ struct CancellableTask ( tauri:: async_runtime:: JoinHandle < ( ) > ) ;
128+
129+ impl Drop for CancellableTask {
130+ fn drop ( & mut self ) {
131+ self . 0 . abort ( ) ;
132+ }
133+ }
0 commit comments