* use redis

* update frontend and switch sanitize library

* changelog

* theming

* docker image

* documentation

* changelog

* clear up limit sizes

* version bump

* version bump
This commit is contained in:
2022-07-16 14:16:54 +02:00
committed by GitHub
parent 0913a8ad0c
commit 9590c9b567
30 changed files with 838 additions and 828 deletions

View File

@@ -1,13 +1,18 @@
use byte_unit::Byte;
// General
lazy_static! {
pub static ref VERSION: String = option_env!("CARGO_PKG_VERSION")
.unwrap_or("Unknown")
.to_string();
pub static ref LIMIT: u32 =
pub static ref VERSION: String = option_env!("CARGO_PKG_VERSION")
.unwrap_or("Unknown")
.to_string();
}
// CONFIG
lazy_static! {
pub static ref LIMIT: usize =
Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string()))
.unwrap()
.get_bytes() as u32;
.get_bytes() as usize;
pub static ref MAX_VIEWS: u32 = std::env::var("MAX_VIEWS")
.unwrap_or("100".to_string())
.parse()
@@ -21,3 +26,15 @@ lazy_static! {
.parse()
.unwrap();
}
// THEME
lazy_static! {
pub static ref THEME_IMAGE: String = std::env::var("THEME_IMAGE")
.unwrap_or("".to_string())
.parse()
.unwrap();
pub static ref THEME_TEXT: String = std::env::var("THEME_TEXT")
.unwrap_or("".to_string())
.parse()
.unwrap();
}

View File

@@ -1,4 +1,7 @@
use actix_web::{middleware, web, App, HttpServer};
use actix_web::{
middleware::{self, Logger},
web, App, HttpServer,
};
use dotenv::dotenv;
#[macro_use]
@@ -15,8 +18,10 @@ mod store;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("warning"));
return HttpServer::new(|| {
App::new()
.wrap(Logger::new("%a \"%r\" %s %b %T"))
.wrap(middleware::Compress::default())
.wrap(middleware::DefaultHeaders::default())
.configure(size::init)

View File

@@ -22,9 +22,11 @@ struct NotePath {
async fn one(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
match note {
None => return HttpResponse::NotFound().finish(),
Some(_) => return HttpResponse::Ok().json(NoteInfo {}),
Ok(Some(_)) => HttpResponse::Ok().json(NoteInfo {}),
Ok(None) => HttpResponse::NotFound().finish(),
Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
}
}
@@ -64,8 +66,10 @@ async fn create(note: web::Json<Note>) -> impl Responder {
}
_ => {}
}
store::set(&id.clone(), &n.clone());
return HttpResponse::Ok().json(CreateResponse { id: id });
match store::set(&id.clone(), &n.clone()) {
Ok(_) => return HttpResponse::Ok().json(CreateResponse { id: id }),
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
}
}
#[delete("/{id}")]
@@ -73,8 +77,9 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
match note {
None => return HttpResponse::NotFound().finish(),
Some(note) => {
Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
Ok(None) => return HttpResponse::NotFound().finish(),
Ok(Some(note)) => {
let mut changed = note.clone();
if changed.views == None && changed.expiration == None {
return HttpResponse::BadRequest().finish();
@@ -84,9 +89,19 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
changed.views = Some(v - 1);
let id = p.id.clone();
if v <= 1 {
store::del(&id);
match store::del(&id) {
Err(e) => {
return HttpResponse::InternalServerError().body(e.to_string())
}
_ => {}
}
} else {
store::set(&id, &changed.clone());
match store::set(&id, &changed.clone()) {
Err(e) => {
return HttpResponse::InternalServerError().body(e.to_string())
}
_ => {}
}
}
}
_ => {}
@@ -96,8 +111,12 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
match changed.expiration {
Some(e) => {
if e < n {
store::del(&p.id.clone());
return HttpResponse::BadRequest().finish();
match store::del(&p.id.clone()) {
Ok(_) => return HttpResponse::BadRequest().finish(),
Err(e) => {
return HttpResponse::InternalServerError().body(e.to_string())
}
}
}
}
_ => {}

View File

@@ -1,18 +1,11 @@
use crate::config;
use actix_web::web;
use byte_unit::Byte;
use mime;
lazy_static! {
pub static ref LIMIT: usize =
Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string()))
.unwrap()
.get_bytes() as usize;
}
pub fn init(cfg: &mut web::ServiceConfig) {
let json = web::JsonConfig::default().limit(*LIMIT);
let json = web::JsonConfig::default().limit(*config::LIMIT);
let plain = web::PayloadConfig::default()
.limit(*LIMIT)
.limit(*config::LIMIT)
.mimetype(mime::STAR_STAR);
cfg.app_data(json).app_data(plain);
}

View File

@@ -2,9 +2,14 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Status {
// General
pub version: String,
// Config
pub max_size: u32,
pub max_views: u32,
pub max_expiration: u32,
pub allow_advanced: bool,
// Theme
pub theme_image: String,
pub theme_text: String,
}

View File

@@ -7,10 +7,12 @@ use crate::status::Status;
async fn get_status() -> impl Responder {
return HttpResponse::Ok().json(Status {
version: config::VERSION.to_string(),
max_size: *config::LIMIT,
max_size: *config::LIMIT as u32,
max_views: *config::MAX_VIEWS,
max_expiration: *config::MAX_EXPIRATION,
allow_advanced: *config::ALLOW_ADVANCED,
theme_image: config::THEME_IMAGE.to_string(),
theme_text: config::THEME_TEXT.to_string(),
});
}

View File

@@ -1,36 +1,55 @@
use memcache;
use redis;
use redis::Commands;
use crate::note::now;
use crate::note::Note;
lazy_static! {
static ref CLIENT: memcache::Client = memcache::connect(format!(
"memcache://{}?timeout=10&tcp_nodelay=true",
std::env::var("MEMCACHE").unwrap_or("127.0.0.1:11211".to_string())
))
.unwrap();
static ref REDIS_CLIENT: String = std::env::var("REDIS")
.unwrap_or("redis://127.0.0.1/".to_string())
.parse()
.unwrap();
}
pub fn set(id: &String, note: &Note) {
fn get_connection() -> Result<redis::Connection, &'static str> {
let client =
redis::Client::open(REDIS_CLIENT.to_string()).map_err(|_| "Unable to connect to redis")?;
client
.get_connection()
.map_err(|_| "Unable to connect to redis")
}
pub fn set(id: &String, note: &Note) -> Result<(), &'static str> {
let serialized = serde_json::to_string(&note.clone()).unwrap();
let expiration: u32 = match note.expiration {
Some(e) => e - now(),
None => 0,
let mut conn = get_connection()?;
conn.set(id, serialized)
.map_err(|_| "Unable to set note in redis")?;
match note.expiration {
Some(e) => {
let seconds = e - now();
conn.expire(id, seconds as usize)
.map_err(|_| "Unable to set expiration on notion")?
}
None => {}
};
CLIENT.set(id, serialized, expiration).unwrap();
Ok(())
}
pub fn get(id: &String) -> Option<Note> {
let value: Option<String> = CLIENT.get(&id).unwrap();
pub fn get(id: &String) -> Result<Option<Note>, &'static str> {
let mut conn = get_connection()?;
let value: Option<String> = conn.get(id).map_err(|_| "Could not load note in redis")?;
match value {
None => return None,
None => return Ok(None),
Some(s) => {
let deserialize: Note = serde_json::from_str(&s).unwrap();
return Some(deserialize);
return Ok(Some(deserialize));
}
}
}
pub fn del(id: &String) {
CLIENT.delete(id).unwrap();
pub fn del(id: &String) -> Result<(), &'static str> {
let mut conn = get_connection()?;
conn.del(id).map_err(|_| "Unable to delete note in redis")?;
Ok(())
}