This commit is contained in:
Miguel da Mota 2024-01-13 01:16:01 +01:00
parent fa8ed2b599
commit d00b8c9718
9 changed files with 226 additions and 37 deletions

View file

@ -24,6 +24,7 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
.wrap(middlewares::cache::Caching)
.service(routes::auth::routes())
// .wrap(middlewares::auth::auth())
.service(routes::playlists::routes())

145
src/middlewares/cache.rs Normal file
View file

@ -0,0 +1,145 @@
use base64::{engine::general_purpose, Engine as _};
use std::{
fs::File,
future::{ready, Ready},
io::Write,
};
use actix_web::{
body::MessageBody,
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
http::{
self,
header::{HeaderName, HeaderValue},
},
web::Bytes,
Error, HttpResponse,
};
use serde::{Deserialize, Serialize};
use sha256::digest;
use futures_util::future::LocalBoxFuture;
#[derive(Serialize, Deserialize)]
struct ResponseCache {
data: ResponseCacheData,
revalidate: u32,
tags: Vec<String>,
url: String,
}
#[derive(Serialize, Deserialize)]
struct ResponseCacheData {
body: String,
status: u16,
}
pub struct Caching;
impl<S, B> Transform<S, ServiceRequest> for Caching
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: MessageBody + std::fmt::Debug,
{
type Response = ServiceResponse<Bytes>;
type Error = Error;
type InitError = ();
type Transform = CachingMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(CachingMiddleware { service }))
}
}
pub struct CachingMiddleware<S> {
service: S,
}
// impl CachingMiddlwareService<S> {
// fn get_cache_file(url: &str) -> File {}
// }
impl<S, B> Service<ServiceRequest> for CachingMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: MessageBody + std::fmt::Debug,
{
type Response = ServiceResponse<Bytes>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let url = digest(req.uri().to_string());
// check if cache file exists
let cache_file = File::open(format!(".api/cache/{url}.json"));
// if it does, check if it's valid
if let Ok(file) = cache_file {
let cache: ResponseCache = serde_json::from_reader(file).unwrap();
// if it's valid, return it
// if cache.revalidate > 0 {
let body = general_purpose::STANDARD_NO_PAD.decode(cache.data.body.as_bytes());
match body {
Ok(body) => {
let mut res =
HttpResponse::new(http::StatusCode::from_u16(cache.data.status).unwrap())
.set_body(Bytes::from(body));
res.headers_mut().insert(
HeaderName::from_static("x-vybr-api"),
HeaderValue::from_static("Hello"),
);
res.headers_mut().insert(
HeaderName::from_static("content-type"),
HeaderValue::from_static("application/json"),
);
return Box::pin(async move {
let res = ServiceResponse::new(req.request().clone(), res);
Ok(res)
});
}
Err(err) => println!("Error decoding body: {:?}", err),
}
}
// otherwise continue.
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
let (req, res) = res.into_parts();
let (res, body) = res.into_parts();
let body_bytes = body.try_into_bytes().unwrap();
let content = general_purpose::STANDARD_NO_PAD.encode(&body_bytes);
let file_content = serde_json::to_string(&ResponseCache {
data: ResponseCacheData {
body: content,
status: res.status().as_u16(),
},
revalidate: 0,
tags: vec![],
url: req.uri().to_string(),
})
.unwrap();
let mut file = File::create(format!(".api/cache/{url}.json")).unwrap();
file.write_all(file_content.as_bytes()).unwrap();
let res = res.set_body(body_bytes);
Ok(ServiceResponse::new(req, res))
})
}
}

View file

@ -1,2 +1,4 @@
pub mod error;
pub mod user;
pub mod cache;

View file

@ -23,9 +23,9 @@ pub struct Playlists {
pub public: bool,
pub playlist_type: String,
pub parent_id: Option<String>,
pub creator_id: String,
pub parent_id: Option<String>,
pub created_at: Option<NaiveDateTime>,
pub updated_at: Option<NaiveDateTime>,

View file

@ -32,12 +32,11 @@ diesel::table! {
#[max_length = 255]
name -> Varchar,
public -> Bool,
#[max_length = 24]
playlist_type -> Varchar,
#[max_length = 24]
parent_id -> Nullable<Varchar>,
#[max_length = 24]
creator_id -> Varchar,
#[max_length = 24]
parent_id -> Nullable<Varchar>,
created_at -> Nullable<Timestamp>,
updated_at -> Nullable<Timestamp>,
}