@@ -7,7 +7,8 @@ use std::{
7
7
collections:: { BTreeSet , HashMap } ,
8
8
fs:: { self , File } ,
9
9
path:: { Path , PathBuf } ,
10
- sync:: { Arc , RwLock } ,
10
+ sync:: { mpsc, Arc , RwLock } ,
11
+ thread:: { self , JoinHandle } ,
11
12
} ;
12
13
13
14
const WINDOW_POS_KEY : & str = "window_pos" ;
@@ -26,26 +27,66 @@ struct ItemStore {
26
27
items : HashMap < String , String > ,
27
28
}
28
29
30
+ #[ derive( Eq , PartialEq ) ]
31
+ enum Message {
32
+ Persist ,
33
+ Exit ,
34
+ }
35
+
29
36
impl ItemStore {
30
- fn persist ( & mut self ) {
37
+ fn persist ( & self ) {
31
38
let file = ok ! ( File :: create( & self . path) ) ;
32
39
ron:: ser:: to_writer_pretty ( file, & self . items , Default :: default ( ) ) . wrest ( ) ;
33
40
}
34
41
}
35
42
43
+ struct ItemStoreThread {
44
+ thread : Option < JoinHandle < ( ) > > ,
45
+ tx : mpsc:: Sender < Message > ,
46
+ }
47
+
48
+ impl Drop for ItemStoreThread {
49
+ fn drop ( & mut self ) {
50
+ self . tx . send ( Message :: Exit ) . wrest ( ) ;
51
+ if let Some ( handle) = self . thread . take ( ) {
52
+ handle. join ( ) . wrest ( ) ;
53
+ }
54
+ }
55
+ }
56
+
36
57
#[ derive( Clone ) ]
37
58
pub struct Config {
38
59
store : Arc < RwLock < ItemStore > > ,
60
+ thread : Arc < ItemStoreThread > ,
39
61
}
40
62
41
63
impl Config {
42
64
pub fn new ( ) -> Option < Self > {
43
65
let path = Self :: path ( ) ?;
44
66
let items = Self :: load ( & path) ;
45
- let store = ItemStore { path, items } ;
46
- Some ( Self {
47
- store : Arc :: new ( RwLock :: new ( store) ) ,
48
- } )
67
+ let store = Arc :: new ( RwLock :: new ( ItemStore { path, items } ) ) ;
68
+ let ( tx, rx) = mpsc:: channel :: < Message > ( ) ;
69
+ let thread = {
70
+ let store = store. clone ( ) ;
71
+ Some ( thread:: spawn ( move || loop {
72
+ // Wait for a message.
73
+ if rx. recv ( ) . wrest ( ) == Message :: Exit {
74
+ return ;
75
+ }
76
+
77
+ // Only the most recent persist message is needed.
78
+ while let Ok ( msg) = rx. try_recv ( ) {
79
+ if msg == Message :: Exit {
80
+ return ;
81
+ }
82
+ }
83
+
84
+ store. read ( ) . wrest ( ) . persist ( ) ;
85
+ } ) )
86
+ } ;
87
+
88
+ let thread = Arc :: new ( ItemStoreThread { thread, tx } ) ;
89
+ Some ( Self { store, thread } )
49
90
}
50
91
51
92
pub fn get_window_pos ( & self ) -> Option < Pos2 > {
@@ -237,16 +278,20 @@ impl Config {
237
278
fn set ( & mut self , key : & str , item : String ) {
238
279
let mut lock = self . store . write ( ) . wrest ( ) ;
239
280
lock. items . insert ( key. to_owned ( ) , item) ;
240
- lock . persist ( ) ;
281
+ self . persist ( ) ;
241
282
}
242
283
243
284
fn remove ( & mut self , key : & str ) {
244
285
let mut lock = self . store . write ( ) . wrest ( ) ;
245
286
if lock. items . remove ( key) . is_some ( ) {
246
- lock . persist ( ) ;
287
+ self . persist ( ) ;
247
288
}
248
289
}
249
290
291
+ fn persist ( & self ) {
292
+ self . thread . tx . send ( Message :: Persist ) . wrest ( ) ;
293
+ }
294
+
250
295
fn get_sota_config_path ( ) -> Option < PathBuf > {
251
296
let path = dirs:: config_dir ( ) ?;
252
297
Some ( path. join ( "Portalarium" ) . join ( "Shroud of the Avatar" ) )
0 commit comments