Talon/src/page.rs

78 lines
2.3 KiB
Rust

use poem::{
error::ResponseError,
handler,
http::{header, StatusCode},
web::{Data, Redirect},
IntoResponse, Request, Response, Result,
};
use crate::{storage::StorageError, util, Talon};
#[derive(thiserror::Error, Debug)]
pub enum PageError {
#[error("invalid subdomain")]
InvalidSubdomain,
#[error("website does not have any version")]
NoVersion,
}
impl ResponseError for PageError {
fn status(&self) -> StatusCode {
StatusCode::NOT_FOUND
}
}
#[handler]
pub async fn page(request: &Request, talon: Data<&Talon>) -> Result<Response> {
let host = request
.header(header::HOST)
.ok_or(PageError::InvalidSubdomain)?;
let (subdomain, vid) =
util::parse_host(host, &talon.cfg.server.root_domain).ok_or(PageError::InvalidSubdomain)?;
let vid = match vid {
Some(vid) => vid,
None => {
let ws = talon.db.get_website(subdomain)?;
ws.latest_version.ok_or(PageError::NoVersion)?
}
};
let (file, ok) =
match talon
.storage
.get_file(subdomain, vid, request.uri().path(), request.headers())
{
Ok(file) => (file, true),
Err(StorageError::NotFound(f)) => {
let version = talon.db.get_version(subdomain, vid)?;
if let Some(fallback) = &version.fallback {
(
talon
.storage
.get_file(subdomain, vid, fallback, request.headers())?,
version.spa,
)
} else if version.spa {
(
talon
.storage
.get_file(subdomain, vid, "", request.headers())?,
true,
)
} else {
return Err(StorageError::NotFound(f).into());
}
}
Err(e) => return Err(e.into()),
};
Ok(match file.rd_path {
Some(rd_path) => Redirect::moved_permanent(rd_path).into_response(),
None => talon
.storage
.file_to_response(file, request.headers(), ok)
.await?
.into_response(),
})
}