bootstrap axum app, handle POST requests
This is an initial API that - takes updates as per what foodoord sends - outputs the current status - persists the status in a file
This commit is contained in:
83
src/main.rs
83
src/main.rs
@ -1,9 +1,84 @@
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
routing::{get, post},
|
||||
Json, Router,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use spaceapi::Status;
|
||||
|
||||
mod status;
|
||||
|
||||
fn main() {
|
||||
let status = status::status();
|
||||
// TODO: Figure out where to ackshully put this.
|
||||
const STATUS_FILE: &str = "status.json";
|
||||
|
||||
let serialized = serde_json::to_string(&status).unwrap();
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// initialize tracing
|
||||
// tracing_subscriber::fmt::init();
|
||||
|
||||
println!("{serialized}");
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
.route("/status.json", get(root))
|
||||
.route("/api/update.php", post(the_doors));
|
||||
|
||||
// run our app with hyper, listening globally on port 3000
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
// Just output the current file. It may cease to exist.
|
||||
async fn root() -> String {
|
||||
// TODO: handle error
|
||||
std::fs::read_to_string(STATUS_FILE).unwrap_or(String::from("KAPOTT"))
|
||||
}
|
||||
|
||||
// Input type for the API: Both fields are optional.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TheDoors {
|
||||
aerie: Option<bool>,
|
||||
cellar: Option<bool>,
|
||||
}
|
||||
|
||||
// The door can see through your soul.
|
||||
// https://www.youtube.com/watch?v=bDQDp00oTP4
|
||||
async fn the_doors(Json(payload): Json<TheDoors>) -> StatusCode {
|
||||
// TODO: handle error
|
||||
let contents = std::fs::read_to_string(STATUS_FILE).expect("FCKAFD");
|
||||
let status: Status = serde_json::from_str(&contents).unwrap();
|
||||
|
||||
if let Some(sens) = status.sensors {
|
||||
// Get the current status as read from the file.
|
||||
let mut doors = sens.door_locked.into_iter();
|
||||
let aerie_current = doors
|
||||
.find(|d| d.metadata.location == "aerie")
|
||||
.unwrap_or(status::get_aerie(false));
|
||||
let cellar_current = doors
|
||||
.find(|d| d.metadata.location == "cellar")
|
||||
.unwrap_or(status::get_cellar(false));
|
||||
|
||||
// New door status: fall back to respective current value if no update
|
||||
// is provided.
|
||||
let aerie = match payload.aerie {
|
||||
Some(s) => s,
|
||||
None => aerie_current.value,
|
||||
};
|
||||
let cellar = match payload.cellar {
|
||||
Some(s) => s,
|
||||
None => cellar_current.value,
|
||||
};
|
||||
|
||||
let new_doors = status::TheDoors { aerie, cellar };
|
||||
let (sensors, state) = status::update(new_doors);
|
||||
|
||||
let s = status::status(sensors, state);
|
||||
let s = serde_json::to_string(&s).unwrap();
|
||||
|
||||
let mut file = File::create(STATUS_FILE).unwrap();
|
||||
file.write_all(s.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
StatusCode::CREATED
|
||||
}
|
||||
|
131
src/status.rs
131
src/status.rs
@ -4,19 +4,24 @@ use spaceapi::{
|
||||
};
|
||||
|
||||
const SPACE_NAME: &str = "Chaospott";
|
||||
const SPACE_LOGO: &str = "https://chaospott.de/images/logo.png";
|
||||
const SPACE_ADDRESS: &str = "Sibyllastr. 9, 45136 Essen, Germany";
|
||||
const SPACE_LOCATION_LAT: f64 = 51.438476;
|
||||
const SPACE_LOCATION_LON: f64 = 7.024991;
|
||||
|
||||
const SPACE_URL: &str = "https://chaospott.de";
|
||||
const SPACE_LOGO: &str = "https://chaospott.de/images/logo.png";
|
||||
|
||||
pub fn status() -> Status {
|
||||
// TODO: Add missing information
|
||||
pub fn status(sensors: Sensors, state: State) -> Status {
|
||||
let mut status = StatusBuilder::v14(SPACE_NAME)
|
||||
.logo(SPACE_LOGO)
|
||||
.url(SPACE_URL)
|
||||
.location(Location {
|
||||
address: Some("Sibyllastr. 9, 45136 Essen, Germany".into()),
|
||||
lat: 51.438476,
|
||||
lon: 7.024991,
|
||||
address: Some(SPACE_ADDRESS.into()),
|
||||
lat: SPACE_LOCATION_LAT,
|
||||
lon: SPACE_LOCATION_LON,
|
||||
..Default::default()
|
||||
})
|
||||
.url(SPACE_URL)
|
||||
.logo(SPACE_LOGO)
|
||||
.contact(Contact {
|
||||
email: Some("info@chaospott.de".into()),
|
||||
irc: Some("irc://irc.hackint.org/#chaospott".into()),
|
||||
@ -30,79 +35,49 @@ pub fn status() -> Status {
|
||||
})
|
||||
// .add_issue_report_channel(IssueReportChannel::IssueMail)
|
||||
// .add_issue_report_channel(IssueReportChannel::Ml)
|
||||
.state(State {
|
||||
open: Some(false),
|
||||
..State::default()
|
||||
})
|
||||
.state(state)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut sensores = Sensors::default();
|
||||
|
||||
sensores.door_locked.push(DoorLockedSensor {
|
||||
value: true,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "aerie".to_string(),
|
||||
},
|
||||
});
|
||||
sensores.door_locked.push(DoorLockedSensor {
|
||||
value: true,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "cellar".to_string(),
|
||||
},
|
||||
});
|
||||
status.sensors = Some(sensores);
|
||||
let mut status = StatusBuilder::v14(SPACE_NAME)
|
||||
.logo(SPACE_LOGO)
|
||||
.url(SPACE_URL)
|
||||
.location(Location {
|
||||
address: Some("Sibyllastr. 9, 45136 Essen, Germany".into()),
|
||||
lat: 51.438476,
|
||||
lon: 7.024991,
|
||||
..Default::default()
|
||||
})
|
||||
.contact(Contact {
|
||||
email: Some("info@chaospott.de".into()),
|
||||
irc: Some("irc://irc.hackint.org/#chaospott".into()),
|
||||
issue_mail: Some("support@chaospott.de".into()),
|
||||
mastodon: Some("https://chaos.social/@chaospott".into()),
|
||||
matrix: Some("#chaospott:matrix.chaospott.de".into()),
|
||||
ml: Some("discuss@lists.chaospott.de".into()),
|
||||
mumble: Some("mumble://mumble.chaospott.de".into()),
|
||||
phone: Some("+49 201 85892243".into()),
|
||||
..Default::default()
|
||||
})
|
||||
// .add_issue_report_channel(IssueReportChannel::IssueMail)
|
||||
// .add_issue_report_channel(IssueReportChannel::Ml)
|
||||
.state(State {
|
||||
open: Some(false),
|
||||
..State::default()
|
||||
})
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut sensores = Sensors::default();
|
||||
|
||||
sensores.door_locked.push(DoorLockedSensor {
|
||||
value: true,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "aerie".to_string(),
|
||||
},
|
||||
});
|
||||
sensores.door_locked.push(DoorLockedSensor {
|
||||
value: true,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "cellar".to_string(),
|
||||
},
|
||||
});
|
||||
status.sensors = Some(sensores);
|
||||
status.sensors = Some(sensors);
|
||||
status
|
||||
}
|
||||
|
||||
pub struct TheDoors {
|
||||
pub aerie: bool,
|
||||
pub cellar: bool,
|
||||
}
|
||||
|
||||
pub fn get_aerie(open: bool) -> DoorLockedSensor {
|
||||
DoorLockedSensor {
|
||||
value: open,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "aerie".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cellar(open: bool) -> DoorLockedSensor {
|
||||
DoorLockedSensor {
|
||||
value: open,
|
||||
metadata: SensorMetadataWithLocation {
|
||||
name: None,
|
||||
description: None,
|
||||
location: "cellar".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(the_doors: TheDoors) -> (Sensors, State) {
|
||||
let mut sensors = Sensors::default();
|
||||
sensors.door_locked.push(get_aerie(the_doors.aerie));
|
||||
sensors.door_locked.push(get_cellar(the_doors.cellar));
|
||||
// Open means that any door is open.
|
||||
let state = State {
|
||||
open: Some(the_doors.aerie || the_doors.cellar),
|
||||
..State::default()
|
||||
};
|
||||
(sensors, state)
|
||||
}
|
||||
|
Reference in New Issue
Block a user