1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use crate::connection::SingleConnection;
use crate::error::RconError;
use crate::error::RconError::{BusyReconnecting, IOError};
use crate::reconnect::Status::{Connected, Disconnected};
enum Status {
Connected(SingleConnection),
Disconnected(String),
}
#[derive(Clone)]
pub struct ReconnectingConnection {
address: String,
pass: String,
connect_timeout: Option<Duration>,
internal: Arc<Mutex<Status>>,
}
impl ReconnectingConnection {
pub fn open<S: Into<String>>(address: S, pass: S, connect_timeout: Option<Duration>) -> Result<Self, RconError> {
let address = address.into();
let pass = pass.into();
let internal = Arc::new(Mutex::new(Connected(SingleConnection::open(address.clone(), pass.clone(), connect_timeout)?)));
Ok(ReconnectingConnection {
address,
pass,
connect_timeout,
internal,
})
}
pub fn exec<S: Into<String>>(&mut self, cmd: S) -> Result<String, RconError> {
let result = {
let mut lock = self.internal.lock().unwrap();
let connection = match lock.deref_mut() {
Connected(ref mut c) => c,
Disconnected(msg) => return Err(BusyReconnecting(msg.clone())),
};
connection.exec(cmd)
};
match result {
Err(e) => match &e {
IOError(_) => Err(self.start_reconnect(e)),
_ => Err(e)
},
Ok(result) => Ok(result)
}
}
fn start_reconnect(&self, e: RconError) -> RconError {
{
let mut lock = self.internal.lock().unwrap();
*lock = Disconnected(e.to_string());
}
let clone = self.clone();
thread::spawn(move || clone.reconnect_loop());
BusyReconnecting(e.to_string())
}
fn reconnect_loop(&self) {
loop {
match SingleConnection::open(self.address.clone(), self.pass.clone(), self.connect_timeout.clone()) {
Err(_) => {
thread::sleep(Duration::from_secs(1));
}
Ok(c) => {
let mut lock = self.internal.lock().unwrap();
*lock = Connected(c);
return;
}
}
}
}
}