mangadex-home-rs/src/cache/mod.rs

167 lines
4.2 KiB
Rust
Raw Normal View History

2021-04-14 19:11:00 -07:00
use std::path::PathBuf;
2021-04-14 19:52:54 -07:00
use std::{fmt::Display, str::FromStr};
2021-04-14 19:11:00 -07:00
use actix_web::http::HeaderValue;
use async_trait::async_trait;
use bytes::Bytes;
use chrono::{DateTime, FixedOffset};
use futures::Stream;
pub use generational::GenerationalCache;
pub use low_mem::LowMemCache;
use self::fs::FromFsStream;
mod fs;
mod generational;
mod low_mem;
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct CacheKey(pub String, pub String, pub bool);
impl Display for CacheKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.2 {
write!(f, "saver/{}/{}", self.0, self.1)
} else {
write!(f, "data/{}/{}", self.0, self.1)
}
}
}
impl From<CacheKey> for PathBuf {
#[inline]
fn from(key: CacheKey) -> Self {
key.to_string().into()
}
}
pub struct CachedImage(pub Bytes);
2021-04-14 19:52:54 -07:00
#[derive(Copy, Clone)]
2021-04-14 19:11:00 -07:00
pub struct ImageMetadata {
2021-04-14 19:52:54 -07:00
pub content_type: Option<ImageContentType>,
2021-04-14 19:11:00 -07:00
pub content_length: Option<usize>,
pub last_modified: Option<DateTime<FixedOffset>>,
}
2021-04-14 19:52:54 -07:00
// Note to self: If these are wrong blame Triscuit 9
#[derive(Copy, Clone)]
pub enum ImageContentType {
Png,
Jpeg,
Gif,
Bmp,
Tif,
}
pub struct InvalidContentType;
impl FromStr for ImageContentType {
type Err = InvalidContentType;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"image/png" => Ok(Self::Png),
"image/jpeg" => Ok(Self::Jpeg),
"image/gif" => Ok(Self::Gif),
"image/bmp" => Ok(Self::Bmp),
"image/tif" => Ok(Self::Tif),
_ => Err(InvalidContentType),
}
}
}
impl AsRef<str> for ImageContentType {
#[inline]
fn as_ref(&self) -> &str {
match self {
Self::Png => "image/png",
Self::Jpeg => "image/jpeg",
Self::Gif => "image/gif",
Self::Bmp => "image/bmp",
Self::Tif => "image/tif",
}
}
}
2021-04-14 19:11:00 -07:00
#[derive(Debug)]
pub enum ImageRequestError {
InvalidContentType,
InvalidContentLength,
InvalidLastModified,
}
impl ImageMetadata {
pub fn new(
content_type: Option<HeaderValue>,
content_length: Option<HeaderValue>,
last_modified: Option<HeaderValue>,
) -> Result<Self, ImageRequestError> {
Ok(Self {
content_type: content_type
2021-04-14 19:52:54 -07:00
.map(|v| match v.to_str() {
Ok(v) => ImageContentType::from_str(v),
Err(_) => Err(InvalidContentType),
})
2021-04-14 19:11:00 -07:00
.transpose()
.map_err(|_| ImageRequestError::InvalidContentType)?,
content_length: content_length
.map(|header_val| {
header_val
.to_str()
.map_err(|_| ImageRequestError::InvalidContentLength)?
.parse()
.map_err(|_| ImageRequestError::InvalidContentLength)
})
.transpose()?,
last_modified: last_modified
.map(|header_val| {
DateTime::parse_from_rfc2822(
header_val
.to_str()
.map_err(|_| ImageRequestError::InvalidLastModified)?,
)
.map_err(|_| ImageRequestError::InvalidLastModified)
})
.transpose()?,
})
}
}
#[async_trait]
pub trait Cache: Send + Sync {
2021-04-14 19:11:00 -07:00
async fn get(&mut self, _key: &CacheKey) -> Option<&(CachedImage, ImageMetadata)> {
unimplemented!()
}
async fn put(&mut self, _key: CacheKey, _image: CachedImage, _metadata: ImageMetadata) {
unimplemented!()
}
async fn get_stream(
&mut self,
_key: &CacheKey,
) -> Option<Result<FromFsStream, std::io::Error>> {
unimplemented!()
}
async fn put_stream(&mut self, _key: CacheKey, _image: ByteStream) {
2021-04-14 19:11:00 -07:00
unimplemented!()
}
}
pub enum ByteStream {}
impl Stream for ByteStream {
type Item = Result<Bytes, reqwest::Error>;
fn poll_next(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
todo!()
}
}