1use super::program::Program;
2use super::protocol::{Message, MessageType};
3use eui48::MacAddress;
4use serde::{Deserialize, Serialize, Serializer};
5use std::collections::HashMap;
6use std::net::{SocketAddr, UdpSocket};
7use std::sync::{Arc, Mutex};
8use std::time::Instant;
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11pub struct DeviceConfig {
12 program: Option<String>,
13 secret: Option<String>,
14}
15
16#[derive(Serialize, Debug, Clone)]
17pub struct DeviceStatus {
18 pub address: SocketAddr,
19 pub program: Option<Program>,
20
21 #[serde(skip)]
22 pub secret: String,
23
24 #[serde(skip)]
25 pub last_seen: Instant,
26}
27
28impl Serialize for Program {
29 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
30 serializer.serialize_bytes(&self.code)
31 }
32}
33
34pub struct ServerState {
35 pub config: HashMap<String, DeviceConfig>,
36 pub devices: HashMap<String, DeviceStatus>,
37 pub socket: UdpSocket,
38}
39
40pub struct Server {
41 state: Arc<Mutex<ServerState>>,
42 default_secret: String,
43 default_program: Program,
44}
45
46impl Server {
47 pub fn new(
48 devices: HashMap<String, DeviceConfig>,
49 default_secret: &str,
50 default_program: Program,
51 bind_address: &str,
52 ) -> std::io::Result<Server> {
53 Ok(Server {
54 state: Arc::new(Mutex::new(ServerState {
55 config: devices,
56 devices: HashMap::new(),
57 socket: UdpSocket::bind(bind_address)?,
58 })),
59 default_secret: default_secret.to_string(),
60 default_program,
61 })
62 }
63
64 pub fn state(&mut self) -> Arc<Mutex<ServerState>> {
65 self.state.clone()
66 }
67
68 pub fn run(&mut self) -> std::io::Result<()> {
69 let socket = {
70 let m = self.state.lock().unwrap();
71 m.socket.try_clone()?
72 };
73
74 loop {
75 let mut buf = [0; 1500];
76 let (amt, source_address) = socket.recv_from(&mut buf)?;
77
78 match Message::peek_mac_address(&buf[0..amt]) {
79 Err(t) => log::error!("\tError reading MAC address: {:?}", t),
80 Ok(mac) => {
81 let canonical_mac = mac.to_canonical();
83 let device_config: Option<DeviceConfig> = {
84 let m = self.state.lock().unwrap();
85 if m.config.contains_key(&canonical_mac) {
86 Some(m.config[&canonical_mac].clone())
87 } else {
88 None
89 }
90 };
91
92 let secret = match &device_config {
94 Some(d) => match &d.secret {
95 Some(s) => s.clone(),
96 None => self.default_secret.clone(),
97 },
98 None => self.default_secret.clone(),
99 };
100
101 match Message::from_buffer(&buf[0..amt], secret.as_bytes()) {
103 Err(t) => log::error!(
104 "{} error {:?} (size={}b source={} secret={:?})",
105 source_address,
106 t,
107 amt,
108 mac,
109 secret
110 ),
111 Ok(msg) => {
112 let mac_identifier = mac.to_canonical();
113 log::info!(
114 "{} @ {}: {:?} t={}",
115 &mac_identifier,
116 &source_address,
117 msg.message_type,
118 msg.unix_time
119 );
120
121 {
123 let mut m = self.state.lock().unwrap();
124 let mut new_status = match m.devices.get(&mac_identifier) {
125 Some(status) => (*status).clone(),
126 None => DeviceStatus {
127 address: source_address,
128 program: None,
129 secret: secret.clone(),
130 last_seen: Instant::now(),
131 },
132 };
133 new_status.last_seen = Instant::now();
134
135 match msg.message_type {
136 MessageType::Ping => {
137 let pong = Message {
138 message_type: MessageType::Pong,
139 unix_time: msg.unix_time,
140 mac_address: MacAddress::nil(),
141 payload: None,
142 };
143
144 let secret_bytes = secret.as_bytes();
146 assert!(
147 Message::from_buffer(
148 &pong.signed(secret_bytes),
149 secret_bytes
150 )
151 .is_ok(),
152 "deserialize own message"
153 );
154
155 if let Err(t) = socket.send_to(
156 &pong.signed(secret.as_bytes()),
157 source_address,
158 ) {
159 println!("Send pong failed: {:?}", t);
160 }
161
162 let device_program = if let Some(p) = new_status.program {
163 p
164 } else if let Some(config) = &device_config {
165 if let Some(path) = &config.program {
166 Program::from_file(&path)
167 .expect("error loading device-specific program")
168 } else {
169 self.default_program.clone()
170 }
171 } else {
172 self.default_program.clone()
173 };
174
175 let run = Message {
176 message_type: MessageType::Run,
177 unix_time: msg.unix_time,
178 mac_address: MacAddress::nil(),
179 payload: Some(device_program.clone().code),
180 };
181
182 new_status.program = Some(device_program);
183
184 if let Err(t) = socket
185 .send_to(&run.signed(secret.as_bytes()), source_address)
186 {
187 println!("Send pong failed: {:?}", t);
188 }
189 }
190 MessageType::Pong => {
191 }
193 _ => {}
194 }
195
196 m.devices.insert(mac_identifier, new_status);
197 }
198 }
199 }
200 }
201 }
202 }
203 }
204}