use poem's new embed endpoints

This commit is contained in:
Eugene Pankov 2022-04-28 17:20:32 -07:00
parent d7791837e3
commit 9b6769548b
No known key found for this signature in database
GPG key ID: 5896FCBBDD1CF4F4
4 changed files with 4 additions and 99 deletions

2
Cargo.lock generated
View file

@ -2234,6 +2234,7 @@ dependencies = [
"cookie", "cookie",
"futures-util", "futures-util",
"headers", "headers",
"hex",
"http", "http",
"httpdate", "httpdate",
"hyper", "hyper",
@ -2247,6 +2248,7 @@ dependencies = [
"priority-queue", "priority-queue",
"rand", "rand",
"regex", "regex",
"rust-embed",
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",

View file

@ -12,7 +12,7 @@ chrono = "0.4"
futures = "0.3" futures = "0.3"
hex = "0.4" hex = "0.4"
mime_guess = {version = "2.0", default_features = false} mime_guess = {version = "2.0", default_features = false}
poem = {version = "^1.3.24", features = ["cookie", "session", "anyhow", "rustls", "websocket"]} poem = {version = "^1.3.24", features = ["cookie", "session", "anyhow", "rustls", "websocket", "embed"]}
poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]} poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]}
russh-keys = {version = "0.22.0-beta.1", features = ["openssl"]} russh-keys = {version = "0.22.0-beta.1", features = ["openssl"]}
rust-embed = "6.3" rust-embed = "6.3"

View file

@ -1,96 +0,0 @@
//! Usage:
//!
//! ```
//! #[derive(RustEmbed)]
//! #[folder = "app/dist"]
//! pub struct Assets;
//!
//! Route::new()
//! .at("/", EmbeddedFileEndpoint::<Assets>::new("index.html"))
//! .nest_no_strip("/assets", EmbeddedFilesEndpoint::<Assets>::new())
//! ```
use async_trait::async_trait;
use poem::http::{header, Method, StatusCode};
use poem::{Endpoint, Request, Response};
use rust_embed::RustEmbed;
use std::marker::PhantomData;
pub struct EmbeddedFileEndpoint<E: RustEmbed + Send + Sync> {
_embed: PhantomData<E>,
path: String,
}
impl<E: RustEmbed + Send + Sync> EmbeddedFileEndpoint<E> {
pub fn new(path: &str) -> Self {
EmbeddedFileEndpoint {
_embed: PhantomData,
path: path.to_owned(),
}
}
}
#[async_trait]
impl<E: RustEmbed + Send + Sync> Endpoint for EmbeddedFileEndpoint<E> {
type Output = Response;
async fn call(&self, req: Request) -> Result<Self::Output, poem::Error> {
if req.method() != Method::GET {
return Err(StatusCode::METHOD_NOT_ALLOWED.into());
}
match E::get(&self.path) {
Some(content) => {
let hash = hex::encode(content.metadata.sha256_hash());
if req
.headers()
.get(header::IF_NONE_MATCH)
.map(|etag| etag.to_str().unwrap_or("000000").eq(&hash))
.unwrap_or(false)
{
return Err(StatusCode::NOT_MODIFIED.into());
}
// otherwise, return 200 with etag hash
let body: Vec<u8> = content.data.into();
let mime = mime_guess::from_path(&self.path).first_or_octet_stream();
Ok(Response::builder()
.header(header::CONTENT_TYPE, mime.as_ref())
.header(header::ETAG, hash)
.body(body))
}
None => Err(StatusCode::NOT_FOUND.into()),
}
}
}
pub struct EmbeddedFilesEndpoint<E: RustEmbed + Send + Sync> {
_embed: PhantomData<E>,
}
impl<E: RustEmbed + Send + Sync> EmbeddedFilesEndpoint<E> {
pub fn new() -> Self {
EmbeddedFilesEndpoint {
_embed: PhantomData,
}
}
}
#[async_trait]
impl<E: RustEmbed + Send + Sync> Endpoint for EmbeddedFilesEndpoint<E> {
type Output = Response;
async fn call(&self, req: Request) -> Result<Self::Output, poem::Error> {
let mut path = req
.uri()
.path()
.trim_start_matches('/')
.trim_end_matches('/')
.to_string();
if path.is_empty() {
path = "index.html".to_string();
}
let path = path.as_ref();
EmbeddedFileEndpoint::<E>::new(path).call(req).await
}
}

View file

@ -1,9 +1,8 @@
#![feature(decl_macro, proc_macro_hygiene, let_else)] #![feature(decl_macro, proc_macro_hygiene, let_else)]
mod api; mod api;
mod embed;
mod helpers; mod helpers;
use crate::embed::{EmbeddedFileEndpoint, EmbeddedFilesEndpoint};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use poem::endpoint::{EmbeddedFilesEndpoint, EmbeddedFileEndpoint};
use poem::listener::{Listener, RustlsConfig, TcpListener}; use poem::listener::{Listener, RustlsConfig, TcpListener};
use poem::middleware::{AddData, SetHeader}; use poem::middleware::{AddData, SetHeader};
use poem::session::{CookieConfig, MemoryStorage, ServerSession}; use poem::session::{CookieConfig, MemoryStorage, ServerSession};