mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2024-12-25 19:28:21 +01:00
Moved to a more genral implementation for the response format.
This commit is contained in:
parent
20fb7ee2ff
commit
a33473fdc9
@ -379,7 +379,7 @@ async fn settings_query_middleware<B>(
|
||||
let ua = user_agent.as_str();
|
||||
for tua in config.template.text_user_agents {
|
||||
if ua.starts_with(&tua) {
|
||||
format = Some(ResponseFormat::TextPlain);
|
||||
format = Some(ResponseFormat::Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -387,7 +387,7 @@ async fn settings_query_middleware<B>(
|
||||
}
|
||||
// Add the request settings extension
|
||||
req.extensions_mut().insert(QuerySettings{
|
||||
format: format.unwrap_or(ResponseFormat::TextHtml),
|
||||
format: format.unwrap_or(ResponseFormat::Html),
|
||||
lang: query.lang.unwrap_or("en".to_string()),
|
||||
available_dns_resolvers: derived_config.dns_resolver_selectables,
|
||||
dns_resolver_id: dns_resolver_id,
|
||||
|
128
src/mycelium/format.rs
Normal file
128
src/mycelium/format.rs
Normal file
@ -0,0 +1,128 @@
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
/// Defines how the response should be rendered.
|
||||
pub enum MycFormatFamily {
|
||||
/// When rendering the templating engine will be invoked
|
||||
Template,
|
||||
/// When rendering the [View](./trait.View.html)
|
||||
/// is asked to generate an API response.
|
||||
API,
|
||||
}
|
||||
|
||||
/// Implement on a type that is able to describe a response format.
|
||||
///
|
||||
/// It is best implemented on an enum.
|
||||
pub trait MycFormat: ToString+Clone+Default {
|
||||
|
||||
// Return the format family this
|
||||
fn get_family(&self) -> MycFormatFamily {
|
||||
match self.get_name().as_str() {
|
||||
"json" => MycFormatFamily::API,
|
||||
_ => MycFormatFamily::Template,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the file extnsion for the format.
|
||||
///
|
||||
/// Used for deriving the path for the template name.
|
||||
///
|
||||
/// Defaults to `.{self.get_name()}`
|
||||
/// with the exception of the name being `text`
|
||||
/// then it defaults to `.txt`.
|
||||
fn get_file_extension(&self) -> String {
|
||||
match self.get_name().as_str() {
|
||||
"text" => ".txt".to_string(),
|
||||
_ => ".".to_owned()+&self.get_name(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the format,
|
||||
/// by default taken from the ToString implementation.
|
||||
fn get_name(&self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
|
||||
/// Allows adding extra mimetypes quickly for prototyping
|
||||
///
|
||||
/// Implementing get_mime_type() properly is recommended
|
||||
/// for production use.
|
||||
fn get_less_well_known_mimetype(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns a textual representation of the Mimetype.
|
||||
///
|
||||
/// It is recommended to implement this when in production use.
|
||||
///
|
||||
/// For prototyping the default implementation makes assumptions
|
||||
/// based on the output of get_name(), falling back
|
||||
/// to get_less_well_known_mimetype() and the "application/octet-stream" type.
|
||||
///
|
||||
/// The default implementation knows the following associations:
|
||||
/// * `text`: `text/plain`
|
||||
/// * `html`: `text/html`
|
||||
/// * `json`: `application/json`
|
||||
/// * `xml`: `application/xml`
|
||||
/// * `rss`: `application/rss+xml`
|
||||
/// * `atom`: `application/atom+xml`
|
||||
///
|
||||
/// *Implementation Note:* It may be possible that two different views
|
||||
/// have the same MimeType (maybe two json representations for different consumers).
|
||||
///
|
||||
fn get_mime_type(&self) -> &'static str {
|
||||
match self.get_name().as_str() {
|
||||
"text" => "text/plain",
|
||||
"html" => "text/html",
|
||||
"json" => "application/json",
|
||||
"xml" => "application/xml",
|
||||
"rss" => "application/rss+xml",
|
||||
"atom" => "application/atom+xml",
|
||||
_ =>
|
||||
self.get_less_well_known_mimetype()
|
||||
.unwrap_or_else(||"application/octet-stream"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a view from its name.
|
||||
fn from_name(name: &str) -> Option<Self>;
|
||||
}
|
||||
|
||||
// Some Sample implementations
|
||||
|
||||
#[derive(Clone,Serialize,Deserialize,Default)]
|
||||
#[serde(rename_all="lowercase")]
|
||||
pub enum HtmlTextJsonFormat {
|
||||
#[default]
|
||||
Html,
|
||||
Text,
|
||||
Json,
|
||||
}
|
||||
|
||||
impl ToString for HtmlTextJsonFormat {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Html => "html",
|
||||
Self::Text => "text",
|
||||
Self::Json => "json",
|
||||
}.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl MycFormat for HtmlTextJsonFormat {
|
||||
|
||||
//TODO: implement other methods to make it more performant
|
||||
|
||||
fn from_name(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"html" => Some(Self::Html),
|
||||
"text" => Some(Self::Text),
|
||||
"json" => Some(Self::Json),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
mod format;
|
||||
mod view;
|
||||
|
||||
pub use self::format::HtmlTextJsonFormat;
|
||||
pub use self::format::MycFormat;
|
||||
pub use self::format::MycFormatFamily;
|
||||
pub use self::view::MycView;
|
||||
|
@ -1,38 +1,11 @@
|
||||
use serde::{Deserialize,Serialize};
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::mycelium::HtmlTextJsonFormat;
|
||||
|
||||
/* Response format */
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Copy)]
|
||||
pub enum ResponseFormat {
|
||||
#[serde(rename="text/plain", alias="text")]
|
||||
TextPlain,
|
||||
#[serde(rename="text/html", alias="html")]
|
||||
TextHtml,
|
||||
#[serde(rename="application/json", alias="json")]
|
||||
ApplicationJson,
|
||||
}
|
||||
|
||||
impl ToString for ResponseFormat {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
ResponseFormat::TextPlain => "text/plain",
|
||||
ResponseFormat::TextHtml => "text/html",
|
||||
ResponseFormat::ApplicationJson => "application/json",
|
||||
}.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseFormat {
|
||||
pub fn to_file_extension(&self) -> String {
|
||||
match self {
|
||||
ResponseFormat::TextPlain => ".txt",
|
||||
ResponseFormat::TextHtml => ".html",
|
||||
ResponseFormat::ApplicationJson => ".json",
|
||||
}.to_string()
|
||||
}
|
||||
}
|
||||
pub type ResponseFormat = HtmlTextJsonFormat;
|
||||
|
||||
/* Query and Template Settings */
|
||||
|
||||
|
@ -19,6 +19,8 @@ use toml::Table;
|
||||
|
||||
use crate::view::View;
|
||||
use crate::mycelium::MycView;
|
||||
use crate::mycelium::MycFormat;
|
||||
use crate::mycelium::MycFormatFamily;
|
||||
use crate::settings::QuerySettings;
|
||||
use crate::settings::ResponseFormat;
|
||||
|
||||
@ -36,8 +38,8 @@ impl Engine {
|
||||
settings: &QuerySettings,
|
||||
view: &View,
|
||||
) -> Response {
|
||||
let mut response = match settings.format {
|
||||
ResponseFormat::TextHtml | ResponseFormat::TextPlain => {
|
||||
let mut response = match settings.format.get_family() {
|
||||
MycFormatFamily::Template => {
|
||||
let template_name = view.get_template_name();
|
||||
|
||||
let mut context = tera::Context::new();
|
||||
@ -50,10 +52,10 @@ impl Engine {
|
||||
context.insert("data", &view);
|
||||
context.insert("extra", &self.template_config);
|
||||
|
||||
match self.tera.render(&(template_name.clone()+&settings.format.to_file_extension()), &context) {
|
||||
match self.tera.render(&(template_name.clone()+&settings.format.get_file_extension()), &context) {
|
||||
Ok(text) =>
|
||||
match settings.format {
|
||||
ResponseFormat::TextHtml => Html(text).into_response(),
|
||||
ResponseFormat::Html => Html(text).into_response(),
|
||||
_ => text.into_response(),
|
||||
}
|
||||
Err(e) => {
|
||||
@ -65,8 +67,7 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: Plain Text should have its own matcher
|
||||
ResponseFormat::ApplicationJson => {
|
||||
MycFormatFamily::API => {
|
||||
match view {
|
||||
View::Dig{result, ..} => {
|
||||
Json(result).into_response()
|
||||
|
Loading…
Reference in New Issue
Block a user