1use std::{
2 io, fs,
3 sync::mpsc::{channel,Receiver,Sender,RecvTimeoutError,TryRecvError},
4 path::PathBuf,
5 time::{SystemTime,Duration},
6};
7
8
9pub struct Resource {
10 text: String,
11 updates: Option<Receiver<String>>,
12}
13impl Resource {
14 pub fn get(&mut self) -> &String {
18 if let Some(rx) = &self.updates {
19 let mut drop_rx = false;
20 loop {
21 match rx.try_recv() {
22 Ok(t) => { self.text = t; },
23 Err(TryRecvError::Empty) => break,
24 Err(TryRecvError::Disconnected) => { drop_rx = true; break },
25 }
26 }
27 if drop_rx { self.updates = None; }
28 }
29 &self.text
30 }
31}
32
33pub struct ResourceManager {
34 sender: Option<Sender<ResourceInner>>,
35 handle: Option<std::thread::JoinHandle<()>>,
36}
37impl Drop for ResourceManager {
38 fn drop(&mut self) {
39 self.sender.take();
40 if let Some(h) = self.handle.take() {
41 h.join().ok();
42 }
43 }
44}
45impl ResourceManager {
46 pub fn new(int: Duration) -> ResourceManager {
47 let (tx,rx) = channel();
48 ResourceManager {
49 sender: Some(tx),
50 handle: Some(std::thread::spawn(move || {
51 let mut inners = Vec::new();
52 loop {
53 match rx.recv_timeout(int) {
54 Ok(inner) => inners.push(inner),
55 Err(RecvTimeoutError::Disconnected) => break,
56 Err(RecvTimeoutError::Timeout) => {},
57 }
58 while let Ok(inner) = rx.try_recv() {
59 inners.push(inner);
60 }
61 for inner in &mut inners {
62 if let Err(e) = inner.check_update() {
63 log::warn!("Update failed for {:?}: {:?}",inner.path,e);
64 }
65 }
66 }
67 })),
68 }
69 }
70 pub fn register(&self, fl: &str, updates: bool) -> Result<Resource,io::Error> {
71 Ok(match updates {
72 false => resource_no_updates(fl)?,
73 true => {
74 let (mut rc,inner) = recource_with_updates(fl)?;
75 match &self.sender {
76 None => { rc.updates = None; },
77 Some(sender) => if let Err(_) = sender.send(inner) {
78 rc.updates = None;
79 },
80 }
81 rc
82 }
83 })
84 }
85 pub fn empty(&self) -> Resource {
86 Resource {
87 text: String::new(),
88 updates: None,
89 }
90 }
91}
92
93
94fn recource_with_updates(fl: &str) -> Result<(Resource,ResourceInner),io::Error> {
95 let path = PathBuf::from(fl);
96 let tm = fs::metadata(&path)?.modified()?;
97 let text = fs::read_to_string(&path)?;
98 let (tx,rx) = channel();
99 Ok((Resource { text, updates: Some(rx) }, ResourceInner { path, tm, sender: Some(tx) }))
100}
101
102fn resource_no_updates(fl: &str) -> Result<Resource,io::Error> {
103 let path = PathBuf::from(fl);
104 let text = fs::read_to_string(&path)?;
105 Ok(Resource { text, updates: None })
106}
107
108struct ResourceInner {
109 path: PathBuf,
110 tm: SystemTime,
111 sender: Option<Sender<String>>,
112}
113impl ResourceInner {
114 fn check_update(&mut self) -> Result<bool,io::Error> {
115 let tm = fs::metadata(&self.path)?.modified()?;
116 let res = tm > self.tm;
117 if res {
118 self.tm = tm;
119 let text = fs::read_to_string(&self.path)?;
120 match &self.sender {
121 None => log::warn!("Resource is non-updatable: {:?}",self.path),
122 Some(sender) => match sender.send(text) {
123 Err(_) => {
124 log::warn!("Resource can't be updated: {:?}",self.path);
125 self.sender = None;
126 },
127 Ok(()) => log::info!("Resource updated: {:?}",self.path),
128 },
129 }
130 }
131 Ok(res)
132 }
133}
134