actix_web_rust_embed_responder/
rust_embed.rs1use base64::{engine::general_purpose::STANDARD_NO_PAD as Base64Encoder, Engine};
2use chrono::TimeZone;
3use rust_embed::EmbeddedFile;
4use std::{borrow::Cow, ops::Deref};
5
6use crate::embed::{EmbedRespondable, EmbedResponse, IntoResponse};
7
8impl From<EmbeddedFile> for EmbedResponse<EmbeddedFile> {
9 fn from(file: EmbeddedFile) -> Self {
10 EmbedResponse {
11 file: Some(file),
12 compress: Default::default(),
13 }
14 }
15}
16
17impl From<Option<EmbeddedFile>> for EmbedResponse<EmbeddedFile> {
18 fn from(file: Option<EmbeddedFile>) -> Self {
19 EmbedResponse {
20 file,
21 compress: Default::default(),
22 }
23 }
24}
25
26impl IntoResponse<EmbeddedFile> for EmbeddedFile {
27 fn into_response(self) -> EmbedResponse<EmbeddedFile> {
28 self.into()
29 }
30}
31
32impl IntoResponse<EmbeddedFile> for Option<EmbeddedFile> {
33 fn into_response(self) -> EmbedResponse<EmbeddedFile> {
34 self.into()
35 }
36}
37
38impl EmbedRespondable for EmbeddedFile {
39 type Data = Cow<'static, [u8]>;
40 type DataGzip = Vec<u8>;
41 type DataBr = Vec<u8>;
42 type ETag = String;
43 type LastModified = String;
44 type MimeType = String;
45
46 fn data(&self) -> Self::Data {
47 self.data.clone()
48 }
49
50 fn data_gzip(&self) -> Option<Self::DataGzip> {
51 None
52 }
53
54 fn data_br(&self) -> Option<Self::DataGzip> {
55 None
56 }
57
58 fn last_modified(&self) -> Option<Self::LastModified> {
59 self.last_modified_timestamp().map(|timestamp| {
60 chrono::Utc
61 .timestamp_opt(timestamp, 0)
62 .unwrap()
63 .to_rfc2822()
64 })
65 }
66
67 fn last_modified_timestamp(&self) -> Option<i64> {
68 self.metadata
69 .last_modified()
70 .and_then(|v| v.try_into().ok())
73 }
74
75 fn etag(&self) -> Self::ETag {
76 format!("\"{}\"", Base64Encoder.encode(self.metadata.sha256_hash()))
77 }
78
79 fn mime_type(&self) -> Option<Self::MimeType> {
80 None
86 }
87}
88
89impl Deref for EmbedResponse<EmbeddedFile> {
90 type Target = Option<EmbeddedFile>;
91
92 fn deref(&self) -> &Self::Target {
93 &self.file
94 }
95}