pad_motion/
client.rs

1use std::thread::JoinHandle;
2use std::sync::Arc;
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::io::Result;
5use std::net::UdpSocket;
6use std::net::SocketAddr;
7use std::sync::Mutex;
8use std::time::Duration;
9use rand::Rng;
10use crossbeam_queue::ArrayQueue;
11use crate::protocol::*;
12
13#[derive(Copy, Clone, Debug, Default)]
14struct Slot {
15  controller_info: ControllerInfo,
16  controller_data: ControllerData,
17  latest_packet_number: u32
18}
19
20#[derive(Copy, Clone, Debug)]
21pub enum ClientEvent {
22  ControllerInfoChanged(ControllerInfo),
23  ControllerDataChanged {
24    controller_info: ControllerInfo,
25    controller_data: ControllerData
26  }
27}
28
29const DEFAULT_PORT: u16 = 3333;
30const DEFAULT_SERVER_PORT: u16 = 26760;
31
32pub trait DsClient {
33  /// Starts background client thread.
34  fn start(self, countinue_running: Arc<AtomicBool>) -> JoinHandle<()>;
35
36  /// Gets currently cached controller info for given slot number.
37  fn controller_info(&self, slot_number: u8) -> ControllerInfo;
38
39  /// Gets currently cached controller data for given slot number.
40  fn controller_data(&self, slot_number: u8) -> ControllerData;
41
42  /// Returns next event in event queue or `None` if empty.
43  fn next_event(&self) -> Option<ClientEvent>;
44}
45
46pub struct Client {
47  server_address: SocketAddr,
48  message_header: MessageHeader,
49  slots: Mutex<[Slot; 4]>,
50  socket: UdpSocket,
51  events: ArrayQueue<ClientEvent>
52}
53
54impl Client {
55  /// Creates new client.
56  /// 
57  /// # Arguments
58  /// 
59  /// * `id` - client ID, pass `None` to use a random number.
60  /// * `address` - client's UDP socket address, if `None` is passed `127.0.0.1:3333` is used.
61  /// * `server_address` - server's UDP socket address, the default (if `None` is passed) is `127.0.0.1:267601`.
62  pub fn new(id: Option<u32>, address: Option<SocketAddr>, server_address: Option<SocketAddr>) -> Result<Client> {
63    let mut rng = rand::thread_rng();
64
65    let client_id = match id {
66      Some(id) => id,
67      None => rng.gen()
68    };
69
70    let message_header = {
71      MessageHeader {
72        source: MessageSource::Client,
73        protocol_version: PROTOCOL_VERSION,
74        message_length: 0,
75        checksum: 0,
76        source_id: client_id
77      }
78    };
79
80    let slots = {
81      let mut slots: [Slot; 4] = [Default::default(); 4];
82      let mut i = 0;
83      for slot in slots.iter_mut() {
84        slot.controller_info.slot = i;
85        i += 1;
86      }
87
88      Mutex::new(slots)
89    };
90
91    let client_address = match address {
92      Some(address) => address,
93      None => SocketAddr::from(([127, 0, 0, 1], DEFAULT_PORT))
94    };
95
96    let server_address = match server_address {
97      Some(address) => address,
98      None => SocketAddr::from(([127, 0, 0, 1], DEFAULT_SERVER_PORT))
99    };
100    let socket = UdpSocket::bind(client_address)?;
101    socket.set_read_timeout(Some(Duration::from_secs_f64(0.2)))?;
102    socket.set_write_timeout(Some(Duration::from_secs_f64(0.2)))?;
103
104    let events = ArrayQueue::new(50);
105
106    Ok(Client {
107      server_address,
108      message_header,
109      slots,
110      socket,
111      events
112    })
113  }
114
115  fn encode_and_send(&self, message: Message) -> Result<()> {
116    let mut encoded_message = vec![];
117    encode_message(&mut encoded_message, message).unwrap();
118  
119    self.socket.send_to(&encoded_message, self.server_address).map(|_amount| ())
120  }
121
122  /// Ask server to send controller info for given slot numbers.
123  /// 
124  /// # Arguments
125  /// 
126  /// * `slot_numbers` - slot numbers to ask info for, must contain at most 4 elements.
127  pub fn request_connected_controllers_info(&self, slot_numbers: &[u8]) -> Result<()> {
128    let slot_numbers = {
129      let mut slots = [0; 4];
130
131      let mut i = 0;
132      for &slot in slot_numbers {
133        slots[i] = slot;
134        i += 1;
135      }
136
137      slots
138    };
139
140    let payload = MessagePayload::ConnectedControllersRequest {
141      amount: slot_numbers.len() as i32,
142      slot_numbers
143    };
144
145    let message = Message {
146      header: self.message_header,
147      message_type: MessageType::ConnectedControllers,
148      payload
149    };
150
151    self.encode_and_send(message)
152  }
153
154  /// Ask server to send controller data for given slot numbers.
155  /// You must call this method periodically if you want server to send data.
156  pub fn request_controller_data(&self, request: ControllerDataRequest) -> Result<()> {
157    let payload = MessagePayload::ControllerDataRequest(request);
158
159    let message = Message {
160      header: self.message_header,
161      message_type: MessageType::ControllerData,
162      payload
163    };
164
165    self.encode_and_send(message)
166  }
167
168  fn handle_response(&self, response: Message) -> Option<ClientEvent> {
169    match response.message_type {
170      MessageType::ProtocolVersion => None,
171      _ => {
172        match response.payload {
173          MessagePayload::ConnectedControllerResponse { controller_info } => {
174            let slot_number = controller_info.slot;
175
176            let mut slots = self.slots.lock().unwrap();
177            if slots[slot_number as usize].controller_info != controller_info {
178              slots[slot_number as usize].controller_info = controller_info;
179
180              let event = ClientEvent::ControllerInfoChanged(controller_info);
181
182              Some(event)
183            } else {
184              None
185            }
186          },
187          MessagePayload::ControllerData { packet_number,
188                                           controller_info,
189                                           controller_data } => {
190            let slot_number = controller_info.slot;
191
192            let mut slots = self.slots.lock().unwrap();
193            
194            let slot = slots[slot_number as usize];
195            if packet_number > slot.latest_packet_number {
196              slots[slot_number as usize].latest_packet_number = packet_number;
197
198              if slot.controller_info != controller_info || slot.controller_data != controller_data {
199                slots[slot_number as usize].controller_info = controller_info;
200                slots[slot_number as usize].controller_data = controller_data;
201  
202                let event = ClientEvent::ControllerDataChanged {
203                  controller_info,
204                  controller_data
205                };
206  
207                Some(event)
208              } else {
209                None
210              }
211            } else {
212              None
213            }
214          }
215          _ => None // ignore response
216        }
217      }
218    }
219  }
220}
221
222impl DsClient for Arc<Client> {
223  fn start(self, countinue_running: Arc<AtomicBool>) -> JoinHandle<()> {
224    let countinue_running = countinue_running.clone();
225
226    std::thread::spawn(move || {
227      let mut buf = [0 as u8; 100];
228      while countinue_running.load(Ordering::SeqCst) {
229        match self.socket.recv_from(&mut buf) {
230          Ok((amount, source)) => {
231            if source == self.server_address {
232              let message = parse_message(MessageSource::Server, &buf[..amount], true);
233              if let Ok(message) = message {
234                let event = self.handle_response(message);
235                if let Some(event) = event {
236                  let _ = self.events.push(event);
237                }
238              }
239            }
240          },
241          _ => ()
242        }
243      }
244    })
245  }
246
247  fn controller_info(&self, slot_number: u8) -> ControllerInfo {
248    assert!(slot_number < 4);
249
250    let slot = self.slots.lock().unwrap()[slot_number as usize];
251
252    slot.controller_info
253  }
254
255  fn controller_data(&self, slot_number: u8) -> ControllerData {
256    assert!(slot_number < 4);
257
258    let slot = self.slots.lock().unwrap()[slot_number as usize];
259
260    slot.controller_data
261  }
262
263  fn next_event(&self) -> Option<ClientEvent> {
264    self.events.pop()
265  }
266}