Update web to serve embedded static files
This commit is contained in:
parent
9ab794a75a
commit
07d43ff6b5
93
Cargo.lock
generated
93
Cargo.lock
generated
@ -1141,6 +1141,41 @@ dependencies = [
|
||||
"uncased",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "6.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb133b9a38b5543fad3807fb2028ea47c5f2b566f4f5e28a11902f1a358348b6"
|
||||
dependencies = [
|
||||
"rocket",
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "6.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4e0f0ced47ded9a68374ac145edd65a6c1fa13a96447b873660b2a568a0fd7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"syn",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "7.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512b0ab6853f7e14e3c8754acb43d6f748bb9ced66aa5915a6553ac8213f7731"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.11"
|
||||
@ -1165,6 +1200,15 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
@ -1533,6 +1577,33 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ufmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a64846ec02b57e9108d6469d98d1648782ad6bb150a95a9baac26900bbeab9d"
|
||||
dependencies = [
|
||||
"ufmt-macros",
|
||||
"ufmt-write",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ufmt-macros"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d337d3be617449165cb4633c8dece429afd83f84051024079f97ad32a9663716"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ufmt-write"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
|
||||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
version = "0.9.7"
|
||||
@ -1577,6 +1648,17 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
@ -1652,8 +1734,10 @@ name = "web"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rocket",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"tokio",
|
||||
"ufmt",
|
||||
"xpin",
|
||||
]
|
||||
|
||||
@ -1673,6 +1757,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -10,3 +10,5 @@ rocket = {version="0.5.0-rc.2", features=["json"]}
|
||||
tokio = {version="1"}
|
||||
xpin={path=".."}
|
||||
serde = {version="1", features=["derive"]}
|
||||
rust-embed = { version = "6.6.0", features = ["rocket"] }
|
||||
ufmt = "0.2.0"
|
||||
|
65
web/src/api.rs
Normal file
65
web/src/api.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use rocket::{get, serde::json::Json, Responder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use xpin::Address;
|
||||
|
||||
#[get("/address?<lat>&<lon>")]
|
||||
pub(crate) fn get_address(lat: Option<String>, lon: Option<String>) -> Result<String, ApiError> {
|
||||
let (lat, lon) = lat.zip(lon).ok_or(ApiError::InvalidRequest(
|
||||
"lat and lon parameters are required",
|
||||
))?;
|
||||
let lat = lat
|
||||
.parse::<f64>()
|
||||
.map_err(|_| ApiError::InvalidRequest("Invalid lat parameter"))?;
|
||||
let lon = lon
|
||||
.parse::<f64>()
|
||||
.map_err(|_| ApiError::InvalidRequest("Invalid lon parameter"))?;
|
||||
|
||||
Ok(Address::from_lat_lon(lat, lon)?.to_string())
|
||||
}
|
||||
|
||||
#[get("/coords?<address>")]
|
||||
pub(crate) fn get_coords(address: Option<String>) -> Result<Json<Coords>, ApiError> {
|
||||
let address = address.ok_or(ApiError::InvalidRequest("address parameter required"))?;
|
||||
|
||||
Address::from_str(&address)
|
||||
.as_ref()
|
||||
.map_err(Into::into)
|
||||
.map(Address::as_lat_lon)
|
||||
.map(Coords::from)
|
||||
.map(Json)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) struct Coords {
|
||||
lat: f64,
|
||||
lon: f64,
|
||||
}
|
||||
|
||||
impl From<(f64, f64)> for Coords {
|
||||
fn from((lat, lon): (f64, f64)) -> Self {
|
||||
Self { lat, lon }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 400)]
|
||||
pub(crate) enum ApiError {
|
||||
#[response(status = 400)]
|
||||
AlgorithmError(String),
|
||||
#[response(status = 400)]
|
||||
InvalidRequest(&'static str),
|
||||
}
|
||||
|
||||
impl From<&xpin::Error> for ApiError {
|
||||
fn from(e: &xpin::Error) -> Self {
|
||||
Self::AlgorithmError(e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<xpin::Error> for ApiError {
|
||||
fn from(e: xpin::Error) -> Self {
|
||||
Self::from(&e)
|
||||
}
|
||||
}
|
@ -1,78 +1,17 @@
|
||||
use std::str::FromStr;
|
||||
mod api;
|
||||
mod static_assets;
|
||||
|
||||
use rocket::{get, routes, serde::json::Json, Responder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use xpin::Address;
|
||||
use rocket::routes;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let _r = rocket::build()
|
||||
// Add the API
|
||||
.mount("/api/v1", routes![get_address, get_coords])
|
||||
.mount("/api/v1", routes![api::get_address, api::get_coords])
|
||||
// Add the webui frontend
|
||||
// TODO: ./mount("/", routes![webui])
|
||||
.mount("/", routes![static_assets::dist])
|
||||
.launch()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[get("/address?<lat>&<lon>")]
|
||||
async fn get_address(lat: Option<String>, lon: Option<String>) -> Result<String, ApiError> {
|
||||
let (lat, lon) = lat.zip(lon).ok_or(ApiError::InvalidRequest(
|
||||
"lat and lon parameters are required",
|
||||
))?;
|
||||
let lat = lat
|
||||
.parse::<f64>()
|
||||
.map_err(|_| ApiError::InvalidRequest("Invalid lat parameter"))?;
|
||||
let lon = lon
|
||||
.parse::<f64>()
|
||||
.map_err(|_| ApiError::InvalidRequest("Invalid lon parameter"))?;
|
||||
|
||||
Ok(Address::from_lat_lon(lat, lon)?.to_string())
|
||||
}
|
||||
|
||||
#[get("/coords?<address>")]
|
||||
async fn get_coords(address: Option<String>) -> Result<Json<Coords>, ApiError> {
|
||||
let address = address.ok_or(ApiError::InvalidRequest("address parameter required"))?;
|
||||
|
||||
Address::from_str(&address)
|
||||
.as_ref()
|
||||
.map_err(Into::into)
|
||||
.map(Address::as_lat_lon)
|
||||
.map(Coords::from)
|
||||
.map(Json)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Coords {
|
||||
lat: f64,
|
||||
lon: f64,
|
||||
}
|
||||
|
||||
impl From<(f64, f64)> for Coords {
|
||||
fn from((lat, lon): (f64, f64)) -> Self {
|
||||
Self { lat, lon }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 400)]
|
||||
enum ApiError {
|
||||
#[response(status = 400)]
|
||||
AlgorithmError(String),
|
||||
#[response(status = 400)]
|
||||
InvalidRequest(&'static str),
|
||||
}
|
||||
|
||||
impl From<&xpin::Error> for ApiError {
|
||||
fn from(e: &xpin::Error) -> Self {
|
||||
Self::AlgorithmError(e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<xpin::Error> for ApiError {
|
||||
fn from(e: xpin::Error) -> Self {
|
||||
Self::from(&e)
|
||||
}
|
||||
}
|
||||
|
30
web/src/static_assets.rs
Normal file
30
web/src/static_assets.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use rocket::get;
|
||||
use rocket::http::ContentType;
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../build/"]
|
||||
struct Asset;
|
||||
|
||||
#[get("/<file..>")]
|
||||
pub(crate) fn dist(file: PathBuf) -> Option<(ContentType, Cow<'static, [u8]>)> {
|
||||
if let Some(a) = Asset::get(&format!("{}", file.display().to_string())) {
|
||||
let content_type = file
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
.and_then(ContentType::from_extension)
|
||||
.unwrap_or(ContentType::Bytes);
|
||||
|
||||
return Some((content_type, a.data));
|
||||
}
|
||||
|
||||
[".html", "index.html"].iter().find_map(|ext| {
|
||||
let p = format!("{}{}", file.display().to_string(), ext);
|
||||
|
||||
Asset::get(&p).map(|a| (ContentType::HTML, a.data))
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user