Skip to content

Commit cbdc3a4

Browse files
committed
Add top-level /setup endpoint
1 parent fdc8ae4 commit cbdc3a4

File tree

3 files changed

+132
-1
lines changed

3 files changed

+132
-1
lines changed

src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ macro_rules! rpc_mod {
180180

181181
pub(crate) mod internal {
182182
// Not really public, needed for a Voldemort trait RetrieavableDevice.
183-
#[derive(PartialEq, Eq, Clone, Copy)]
183+
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy)]
184184
pub enum DeviceType {
185185
$(
186186
#[cfg(feature = $path)]

src/server/mod.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use axum::response::IntoResponse;
2828
use axum::routing::MethodFilter;
2929
use axum::{BoxError, Router};
3030
use net_literals::addr;
31+
use std::collections::BTreeMap;
32+
use std::fmt::Write;
3133
use std::future::Future;
3234
use std::net::SocketAddr;
3335
use std::pin::Pin;
@@ -216,6 +218,7 @@ impl Server {
216218
self.bind().await?.start().await
217219
}
218220

221+
#[allow(clippy::too_many_lines)]
219222
fn into_router(self) -> Router {
220223
let devices = Arc::new(self.devices);
221224
let server_info = Arc::new(self.info);
@@ -248,6 +251,68 @@ impl Server {
248251
})
249252
}),
250253
)
254+
.route("/setup", {
255+
let this = Arc::clone(&devices);
256+
257+
axum::routing::get(|| async move {
258+
let mut grouped_devices = BTreeMap::new();
259+
for (device, number) in this.iter_all() {
260+
let device = device.to_configured_device(number);
261+
262+
grouped_devices
263+
.entry(device.ty)
264+
.or_insert_with(Vec::new)
265+
.push((number, device.name));
266+
}
267+
268+
let mut devices_html = String::new();
269+
270+
for (device_type, devices) in grouped_devices {
271+
writeln!(devices_html, "<figure>").unwrap();
272+
writeln!(devices_html, "<figcaption>{}</figcaption>", match device_type {
273+
#[cfg(feature = "camera")]
274+
DeviceType::Camera => "Cameras",
275+
#[cfg(feature = "dome")]
276+
DeviceType::Dome => "Domes",
277+
#[cfg(feature = "filterwheel")]
278+
DeviceType::FilterWheel => "Filter wheels",
279+
#[cfg(feature = "focuser")]
280+
DeviceType::Focuser => "Focusers",
281+
#[cfg(feature = "observingconditions")]
282+
DeviceType::ObservingConditions => "Weather stations",
283+
#[cfg(feature = "rotator")]
284+
DeviceType::Rotator => "Rotators",
285+
#[cfg(feature = "safetymonitor")]
286+
DeviceType::SafetyMonitor => "Safety monitors",
287+
#[cfg(feature = "switch")]
288+
DeviceType::Switch => "Switches",
289+
#[cfg(feature = "telescope")]
290+
DeviceType::Telescope => "Telescopes",
291+
#[cfg(feature = "covercalibrator")]
292+
DeviceType::CoverCalibrator => "Cover calibrators",
293+
}).unwrap();
294+
writeln!(devices_html, "<ul>").unwrap();
295+
for (device_index, device_name) in devices {
296+
writeln!(
297+
devices_html,
298+
r#"<li><a href="/api/v1/{group_path}/{device_index}/setup">{device_name}</a></li>"#,
299+
group_path = DevicePath(device_type),
300+
).unwrap();
301+
}
302+
writeln!(devices_html, "</ul>").unwrap();
303+
writeln!(devices_html, "</figure>").unwrap();
304+
}
305+
306+
axum::response::Html(include_str!("setup_template.html").replace(
307+
"<!-- devices_html -->",
308+
if devices_html.is_empty() {
309+
"<p>No devices are registered on this server.</p>"
310+
} else {
311+
&devices_html
312+
},
313+
))
314+
})
315+
})
251316
.route(
252317
"/api/v1/:device_type/:device_number/:action",
253318
axum::routing::on(

src/server/setup_template.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<meta charset="UTF-8" />
6+
<title>Alpaca devices</title>
7+
<style>
8+
body {
9+
font-family: Arial, sans-serif;
10+
margin: 0;
11+
padding: 0;
12+
}
13+
h1,
14+
figure {
15+
margin: 1em auto;
16+
width: 90vw;
17+
}
18+
h1 {
19+
text-align: center;
20+
color: #333;
21+
font-size: 2.5em;
22+
}
23+
figure {
24+
background-color: #fff;
25+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 -2px 2px rgba(0, 0, 0, 0.3);
26+
}
27+
figcaption,
28+
a {
29+
margin: 0;
30+
padding: 0.625em;
31+
}
32+
figcaption {
33+
background-color: #f5f5f5;
34+
color: #333;
35+
font-size: 1.2em;
36+
}
37+
ul {
38+
list-style: none;
39+
padding: 0;
40+
margin: 0;
41+
display: flex;
42+
flex-direction: column;
43+
}
44+
li:first-child {
45+
border-top: 1px solid #ccc;
46+
}
47+
li {
48+
border-bottom: 1px solid #ccc;
49+
}
50+
a {
51+
color: #333;
52+
text-decoration: none;
53+
display: block;
54+
transition: background-color 0.3s ease;
55+
}
56+
a:hover {
57+
background-color: #f5f5f5;
58+
}
59+
</style>
60+
</head>
61+
<body>
62+
<h1>Alpaca devices</h1>
63+
64+
<!-- devices_html -->
65+
</body>
66+
</html>

0 commit comments

Comments
 (0)