mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2024-12-26 03:38: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();
|
let ua = user_agent.as_str();
|
||||||
for tua in config.template.text_user_agents {
|
for tua in config.template.text_user_agents {
|
||||||
if ua.starts_with(&tua) {
|
if ua.starts_with(&tua) {
|
||||||
format = Some(ResponseFormat::TextPlain);
|
format = Some(ResponseFormat::Text);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,7 +387,7 @@ async fn settings_query_middleware<B>(
|
|||||||
}
|
}
|
||||||
// Add the request settings extension
|
// Add the request settings extension
|
||||||
req.extensions_mut().insert(QuerySettings{
|
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()),
|
lang: query.lang.unwrap_or("en".to_string()),
|
||||||
available_dns_resolvers: derived_config.dns_resolver_selectables,
|
available_dns_resolvers: derived_config.dns_resolver_selectables,
|
||||||
dns_resolver_id: dns_resolver_id,
|
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;
|
mod view;
|
||||||
|
|
||||||
|
pub use self::format::HtmlTextJsonFormat;
|
||||||
|
pub use self::format::MycFormat;
|
||||||
|
pub use self::format::MycFormatFamily;
|
||||||
pub use self::view::MycView;
|
pub use self::view::MycView;
|
||||||
|
@ -1,38 +1,11 @@
|
|||||||
use serde::{Deserialize,Serialize};
|
use serde::{Deserialize,Serialize};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use crate::mycelium::HtmlTextJsonFormat;
|
||||||
|
|
||||||
/* Response format */
|
/* Response format */
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Copy)]
|
pub type ResponseFormat = HtmlTextJsonFormat;
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Query and Template Settings */
|
/* Query and Template Settings */
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ use toml::Table;
|
|||||||
|
|
||||||
use crate::view::View;
|
use crate::view::View;
|
||||||
use crate::mycelium::MycView;
|
use crate::mycelium::MycView;
|
||||||
|
use crate::mycelium::MycFormat;
|
||||||
|
use crate::mycelium::MycFormatFamily;
|
||||||
use crate::settings::QuerySettings;
|
use crate::settings::QuerySettings;
|
||||||
use crate::settings::ResponseFormat;
|
use crate::settings::ResponseFormat;
|
||||||
|
|
||||||
@ -36,8 +38,8 @@ impl Engine {
|
|||||||
settings: &QuerySettings,
|
settings: &QuerySettings,
|
||||||
view: &View,
|
view: &View,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let mut response = match settings.format {
|
let mut response = match settings.format.get_family() {
|
||||||
ResponseFormat::TextHtml | ResponseFormat::TextPlain => {
|
MycFormatFamily::Template => {
|
||||||
let template_name = view.get_template_name();
|
let template_name = view.get_template_name();
|
||||||
|
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
@ -50,10 +52,10 @@ impl Engine {
|
|||||||
context.insert("data", &view);
|
context.insert("data", &view);
|
||||||
context.insert("extra", &self.template_config);
|
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) =>
|
Ok(text) =>
|
||||||
match settings.format {
|
match settings.format {
|
||||||
ResponseFormat::TextHtml => Html(text).into_response(),
|
ResponseFormat::Html => Html(text).into_response(),
|
||||||
_ => text.into_response(),
|
_ => text.into_response(),
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -65,8 +67,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: Plain Text should have its own matcher
|
MycFormatFamily::API => {
|
||||||
ResponseFormat::ApplicationJson => {
|
|
||||||
match view {
|
match view {
|
||||||
View::Dig{result, ..} => {
|
View::Dig{result, ..} => {
|
||||||
Json(result).into_response()
|
Json(result).into_response()
|
||||||
|
Loading…
Reference in New Issue
Block a user