1use serde::Deserialize;
4use std::string::ToString;
5use std::time::Duration;
6
7pub struct RequestConfig {
9 pub host: String,
11 pub port: String,
13 pub vehicle_name: String,
15 pub vehicle_model: String,
17 pub timeout: Duration,
19 pub debugging: bool,
21}
22
23impl RequestConfig {
24 pub fn new() -> Self {
26 Self {
27 host: "127.0.0.1".to_string(),
28 port: "37337".to_string(),
29 vehicle_name: "Current".to_string(),
30 vehicle_model: "Current".to_string(),
31 timeout: Duration::from_millis(300),
32 debugging: false,
33 }
34 }
35 pub fn host(mut self, host: String) -> Self {
37 self.host = host;
38 self
39 }
40
41 pub fn port(mut self, port: String) -> Self {
43 self.port = port;
44 self
45 }
46 pub fn vehicle_name(mut self, vehicle_name: String) -> Self {
48 self.vehicle_name = vehicle_name;
49 self
50 }
51 pub fn vehicle_model(mut self, vehicle_model: String) -> Self {
53 self.vehicle_model = vehicle_model;
54 self
55 }
56
57 pub fn timeout(mut self, timeout: Duration) -> Self {
59 self.timeout = timeout;
60 self
61 }
62 pub fn debugging(mut self, debugging: bool) -> Self {
64 self.debugging = debugging;
65 self
66 }
67}
68
69#[derive(Deserialize, Debug, PartialEq)]
71pub struct ApiWorldType {
72 #[serde(rename = "LevelName")]
74 pub level_name: String,
75 #[serde(rename = "DateTime")]
77 pub date_time: String,
78 #[serde(rename = "TimeFactor")]
80 pub time_factor: f32,
81 #[serde(rename = "BaseLatitude")]
83 pub base_latitude: f64,
84 #[serde(rename = "BaseLongitude")]
86 pub base_longitude: f64,
87}
88
89#[derive(Deserialize, Debug, PartialEq, Default)]
91pub struct ApiVehicleType {
92 #[serde(rename = "ActorName")]
94 pub actor_name: String,
95 #[serde(rename = "VehicleModel")]
97 pub vehicle_model: String,
98 #[serde(rename = "IgnitionEnabled")]
100 pub ignition_enabled: String,
101 #[serde(rename = "EngineStarted")]
103 pub engine_started: String,
104 #[serde(rename = "WarningLights")]
106 pub warning_lights: String,
107 #[serde(rename = "PassengerDoorsOpen")]
109 pub passenger_doors_open: String,
110 #[serde(rename = "FixingBrake")]
112 pub fixing_brake: String,
113 #[serde(rename = "Speed")]
115 pub speed: f32,
116 #[serde(rename = "AllowedSpeed")]
118 pub allowed_speed: f32,
119 #[serde(rename = "DisplayFuel")]
121 pub display_fuel: f32,
122 #[serde(rename = "IndicatorState")]
124 pub indicator_state: i8,
125 #[serde(rename = "AllLamps")]
127 pub all_lamps: ApiLamps,
128 #[serde(rename = "Buttons", default)]
130 pub buttons: Vec<ApiButton>,
131}
132
133#[derive(Deserialize, Debug, PartialEq, Default)]
135pub struct ApiLamps {
136 #[serde(
137 rename = "LightHeadlight",
138 alias = "LightHeadlight1",
139 alias = "Light Headlight"
140 )]
141 pub light_headlight: f32,
142 #[serde(
143 rename = "Light Parking",
144 alias = "LightParking1",
145 alias = "LightParking"
146 )]
147 pub light_parking: f32,
148 #[serde(
149 rename = "Light MAIN",
150 alias = "Light Main",
151 alias = "LightMain",
152 default
153 )] pub light_main: f32,
155 #[serde(
157 rename = "LightTraveling",
158 alias = "LightTraveling1",
159 alias = "Light Travelling"
160 )]
161 pub traveller_light: f32,
162 #[serde(rename = "Door Button 1", alias = "ButtonLight Door 1")]
164 pub front_door_light: f32,
165 #[serde(
167 rename = "Door Button 2",
168 alias = "ButtonLight Door 2",
169 alias = "LightDoorMiddle"
170 )]
171 pub second_door_light: f32,
172 #[serde(rename = "Door Button 3", alias = "ButtonLight Door 3", default)]
174 pub third_door_light: f32,
175 #[serde(rename = "Door Button 4", alias = "ButtonLight Door 4", default)]
177 pub fourth_door_light: f32,
178 #[serde(
180 rename = "LED StopRequest",
181 alias = "DB Stop Request",
182 alias = "TachoStopRequest",
183 default
184 )] pub led_stop_request: f32,
186 #[serde(rename = "ButtonLight BusStopBrake", alias = "LED Stop Brake", default)]
188 pub light_stopbrake: f32,
190 #[serde(
191 rename = "ButtonLight DoorClearance",
192 alias = "DoorClearanceButton",
193 default
194 )] pub door_clearance_light: f32,
196}
197
198#[derive(Deserialize, Debug, PartialEq, Default, Clone)]
200pub struct ApiButton {
201 #[serde(rename = "Name")]
203 pub name: String,
204 #[serde(rename = "Tooltip", default)]
206 pub tooltip: String,
207 #[serde(rename = "State", default)]
209 pub state: String,
210 #[serde(rename = "Value", default)]
212 pub value: String,
213 #[serde(rename = "Actions", default)]
215 pub actions: Vec<String>,
216 #[serde(rename = "States", default)]
218 pub states: Vec<String>,
219}
220
221impl ApiVehicleType {
222
223 pub fn new() -> Self {
224 Self::default()
225 }
226
227 pub fn get_button(&self, name: &str) -> Option<ApiButton> {
229 self.buttons.iter().find(|b| b.name == name).cloned()
230 }
231 pub fn get_button_state(&self, name: &str) -> String {
233 self.buttons
234 .iter()
235 .find(|b| b.name == name)
236 .map(|b| b.state.clone())
237 .unwrap_or_else(|| "".to_string())
238 }
239
240 pub fn get_button_state_contains(&self, part: &str) -> String {
242 self.buttons
243 .iter()
244 .find(|b| b.name.contains(part))
245 .map(|b| b.state.clone())
246 .unwrap_or_else(|| "".to_string())
247 }
248
249 pub fn filtered_buttons(&self, name: &str) -> Vec<ApiButton> {
251 self.buttons
252 .iter()
253 .filter(|b| b.name == name)
254 .cloned()
255 .collect()
256 }
257
258 pub fn retain_buttons_by_name(&mut self, name: &str) {
260 self.buttons.retain(|b| b.name == name);
261 }
262
263 pub fn buttons_name_state(&self) -> Vec<(String, String)> {
265 self.buttons
266 .iter()
267 .map(|b| (b.name.clone(), b.state.clone()))
268 .collect()
269 }
270}
271
272pub async fn send_telemetry_bus_cmd(
274 config: &RequestConfig,
275 cmd: &str,
276) -> Result<(), Box<dyn std::error::Error>> {
277 let url = format!(
278 "http://{}:{}/vehicles/{}/{}",
279 config.host, config.port, config.vehicle_name, cmd
280 );
281 if config.debugging {
282 println!("send_telemetry_bus_cmd URL: {}", url);
283 }
284
285 let _ = reqwest::Client::new()
286 .get(url)
287 .timeout(config.timeout)
288 .send()
289 .await?;
290
291 Ok(())
292}
293
294pub async fn get_telemetry_data(
296 config: &RequestConfig,
297 path: &str,
298) -> reqwest::Result<serde_json::Value> {
299 let url = format!("http://{}:{}/{}", config.host, config.port, path);
300
301 if config.debugging {
302 println!("get_telemetry_data URL: {}", url);
303 }
304
305 let value = reqwest::Client::new()
306 .get(url)
307 .timeout(config.timeout)
308 .send()
309 .await?
310 .json::<serde_json::Value>()
311 .await?;
312
313 Ok(value)
314}
315
316pub async fn get_current_vehicle_name(config: &RequestConfig) -> String {
319 let result = get_telemetry_data(&config, "player").await;
320
321 if result.is_err() {
322 return "".to_string();
323 }
324 let data = result.unwrap();
325
326 if config.debugging {
327 println!("get_current_vehicle_name data: {:?}", data);
328 }
329
330 let mode: Option<String> = data
331 .get("Mode")
332 .and_then(|v| v.as_str())
333 .map(|s| s.to_string());
334
335 let mut mo = "".to_string();
336 if let Some(ref m) = mode {
337 mo = m.clone();
338 }
339
340 if mo != "Vehicle" {
341 return "".to_string();
342 }
343
344 let current_vehicle: Option<String> = data
345 .get("CurrentVehicle")
346 .and_then(|v| v.as_str())
347 .map(|s| s.to_string());
348
349 let mut bus = "".to_string();
350
351 if let Some(ref cv) = current_vehicle {
352 bus = cv.clone();
353 }
354 bus
355}
356
357pub async fn get_vehicle(
359 config: &RequestConfig,
360) -> Result<ApiVehicleType, Box<dyn std::error::Error>> {
361 let path = format!("vehicles/{}", config.vehicle_name);
362
363 if config.debugging {
364 println!("get_vehicle path: {}", path);
365 }
366
367 let body = get_telemetry_data(&config, &path).await?;
368
369 let api_vehicle: ApiVehicleType = serde_json::from_value(body).map_err(|e| {
370 eprintln!("Failed to parse API response as Vehicle JSON: {}", e);
371 Box::new(e) as Box<dyn std::error::Error>
372 })?;
373
374 if config.debugging {
375 println!("{:?}", &api_vehicle);
376 }
377
378 Ok(api_vehicle)
379}
380
381pub async fn get_world(config: &RequestConfig) -> Result<ApiWorldType, Box<dyn std::error::Error>> {
383 let path = "world";
384
385 if config.debugging {
386 println!("get_world path: {}", path);
387 }
388
389 let body = get_telemetry_data(&config, &path).await?;
390
391 let api_world: ApiWorldType = serde_json::from_value(body).map_err(|e| {
392 eprintln!("Failed to parse API response as World JSON: {}", e);
393 Box::new(e) as Box<dyn std::error::Error>
394 })?;
395
396 if config.debugging {
397 println!("{:?}", &api_world);
398 }
399 Ok(api_world)
400}
401
402pub fn get_button_by_name(data: &serde_json::Value, name: &str) -> String {
404 let ret = data
405 .get("Buttons")
406 .and_then(|v| v.as_array())
407 .and_then(|arr| {
408 arr.iter().find(|entry| {
409 entry
410 .get("Name")
411 .and_then(|n| n.as_str())
412 .map_or(false, |s| s == name)
413 })
414 })
415 .and_then(|entry| entry.get("State"))
416 .and_then(|v| v.as_str())
417 .map(|s| s.to_string());
418
419 ret.unwrap_or_else(|| "".to_string())
420}