updates
This commit is contained in:
parent
fa8ed2b599
commit
d00b8c9718
9 changed files with 226 additions and 37 deletions
|
@ -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
145
src/middlewares/cache.rs
Normal 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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,2 +1,4 @@
|
|||
pub mod error;
|
||||
pub mod user;
|
||||
|
||||
pub mod cache;
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue