memcached

This commit is contained in:
cupcakearmy 2021-05-02 03:07:08 +02:00
parent 3f52f00da3
commit 6159e2b67f
No known key found for this signature in database
GPG Key ID: D28129AE5654D9D9
5 changed files with 200 additions and 46 deletions

101
Cargo.lock generated
View File

@ -477,6 +477,7 @@ dependencies = [
"actix-web", "actix-web",
"bs62", "bs62",
"lazy_static", "lazy_static",
"memcache",
"ring", "ring",
"serde", "serde",
"serde_json", "serde_json",
@ -536,6 +537,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "enum_dispatch"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44bead1f97ab8e54cd4f9205571b5c2c6f18abaa9193f9fdcf7fe09ddd4be313"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.20" version = "1.0.20"
@ -554,6 +567,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.1" version = "1.0.1"
@ -901,6 +929,20 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memcache"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c85d68ede7335fcbd6908253f90314ddfc4afb6bf79ec24833fe30f94cd48a1"
dependencies = [
"byteorder",
"enum_dispatch",
"openssl",
"r2d2",
"rand",
"url",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.4" version = "2.3.4"
@ -1028,6 +1070,33 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"foreign-types",
"libc",
"once_cell",
"openssl-sys",
]
[[package]]
name = "openssl-sys"
version = "0.9.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.1" version = "0.11.1"
@ -1117,6 +1186,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.10" version = "0.2.10"
@ -1159,6 +1234,17 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "r2d2"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f"
dependencies = [
"log",
"parking_lot",
"scheduled-thread-pool",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.7.3" version = "0.7.3"
@ -1266,6 +1352,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "scheduled-thread-pool"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7"
dependencies = [
"parking_lot",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1696,6 +1791,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "vcpkg"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.3"

View File

@ -13,3 +13,4 @@ serde_json = "1"
lazy_static = "1" lazy_static = "1"
ring = "0.16" ring = "0.16"
bs62 = "0.1" bs62 = "0.1"
memcache = "0.15"

8
docker-compose.yml Normal file
View File

@ -0,0 +1,8 @@
version: '3.7'
services:
memcached:
image: memcached:1-alpine
entrypoint: memcached -m 128
ports:
- 11211:11211

View File

@ -7,14 +7,19 @@ pub struct Note {
pub contents: String, pub contents: String,
pub password: bool, pub password: bool,
pub views: Option<u8>, pub views: Option<u8>,
pub expiration: Option<u16>, pub expiration: Option<u64>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct PubNote { pub struct NoteInfo {
pub password: bool, pub password: bool,
} }
#[derive(Serialize, Deserialize, Clone)]
pub struct NotePublic {
pub contents: String,
}
pub fn generate_id() -> String { pub fn generate_id() -> String {
let mut id: [u8; 64] = [0; 64]; let mut id: [u8; 64] = [0; 64];
let sr = ring::rand::SystemRandom::new(); let sr = ring::rand::SystemRandom::new();

View File

@ -1,24 +1,40 @@
use actix_web::{delete, get, post, web, HttpResponse, Responder}; use actix_web::{delete, get, post, web, HttpResponse, Responder};
use memcache;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::time::SystemTime;
use std::sync::Mutex;
use crate::note::{generate_id, Note, PubNote}; use crate::note::{generate_id, Note, NoteInfo, NotePublic};
fn now() -> u64 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
}
lazy_static! { lazy_static! {
static ref RAM: Mutex<HashMap<String, Note>> = { static ref CLIENT: memcache::Client =
let mut m = HashMap::new(); memcache::connect("memcache://127.0.0.1:11211?timeout=10&tcp_nodelay=true").unwrap();
m.insert( }
"test".to_string(),
Note { fn set(id: &String, note: &Note) {
contents: "some stuff".to_string(), let serialized = serde_json::to_string(&note.clone()).unwrap();
password: false, CLIENT.set(id, serialized, 0).unwrap();
views: Some(1), }
expiration: Some(100),
}, fn get(id: &String) -> Option<Note> {
); let value: Option<String> = CLIENT.get(&id).unwrap();
return Mutex::new(m); match value {
}; None => return None,
Some(s) => {
let deserialize: Note = serde_json::from_str(&s).unwrap();
return Some(deserialize);
}
}
}
fn del(id: &String) {
CLIENT.delete(id).unwrap();
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -28,25 +44,18 @@ struct NotePath {
#[get("/notes/{id}")] #[get("/notes/{id}")]
async fn one(path: web::Path<NotePath>) -> impl Responder { async fn one(path: web::Path<NotePath>) -> impl Responder {
let ram = RAM.lock().unwrap();
let p = path.into_inner(); let p = path.into_inner();
let note = ram.get(&p.id); let note = get(&p.id);
match note { match note {
None => return HttpResponse::NotFound().finish(), None => return HttpResponse::NotFound().finish(),
Some(note) => { Some(note) => {
return HttpResponse::Ok().json(PubNote { return HttpResponse::Ok().json(NoteInfo {
password: note.password, password: note.password,
}) })
} }
} }
} }
#[get("/notes/")]
async fn all() -> impl Responder {
let values: Vec<Note> = RAM.lock().unwrap().values().cloned().collect();
return HttpResponse::Ok().json(values);
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct CreateResponse { struct CreateResponse {
id: String, id: String,
@ -54,38 +63,69 @@ struct CreateResponse {
#[post("/notes/")] #[post("/notes/")]
async fn create(note: web::Json<Note>) -> impl Responder { async fn create(note: web::Json<Note>) -> impl Responder {
let n = note.into_inner(); let mut n = note.into_inner();
let id = generate_id(); let id = generate_id();
RAM.lock().unwrap().insert(id.clone(), n.clone()); let bad_req = HttpResponse::BadRequest().finish();
if n.views == None && n.expiration == None {
return bad_req;
}
match n.views {
Some(v) => {
if v > 100 {
return bad_req;
}
}
_ => {}
}
match n.expiration {
Some(e) => {
if e > 360 {
return bad_req;
}
n.expiration = Some(now() + (e * 60))
}
_ => {}
}
set(&id.clone(), &n.clone());
return HttpResponse::Ok().json(CreateResponse { id: id }); return HttpResponse::Ok().json(CreateResponse { id: id });
} }
#[delete("/notes/{id}")] #[delete("/notes/{id}")]
async fn delete(path: web::Path<NotePath>) -> impl Responder { async fn delete(path: web::Path<NotePath>) -> impl Responder {
let mut ram = RAM.lock().unwrap();
let p = path.into_inner(); let p = path.into_inner();
let note = ram.get(&p.id); let note = get(&p.id);
match note { match note {
None => return HttpResponse::NotFound().finish(), None => return HttpResponse::NotFound().finish(),
Some(note) => { Some(note) => {
let mut changed = note.clone(); let mut changed = note.clone();
if changed.views == None && changed.expiration == None { if changed.views == None && changed.expiration == None {
return HttpResponse::BadRequest().finish(); return HttpResponse::BadRequest().finish();
} else { }
match changed.views { match changed.views {
Some(v) => { Some(v) => {
changed.views = Some(v - 1); changed.views = Some(v - 1);
let id = p.id.clone();
if v <= 1 { if v <= 1 {
ram.remove(&p.id); del(&id);
} else { } else {
ram.insert(p.id, changed.clone()); set(&id, &changed.clone());
} }
} }
_ => {} _ => {}
} }
return HttpResponse::Ok().json(changed); match changed.expiration {
Some(e) => {
if e > now() {
del(&p.id.clone());
return HttpResponse::BadRequest().finish();
} }
} }
_ => {}
}
return HttpResponse::Ok().json(NotePublic {
contents: changed.contents,
});
}
} }
} }
@ -93,5 +133,4 @@ pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(create); cfg.service(create);
cfg.service(delete); cfg.service(delete);
cfg.service(one); cfg.service(one);
cfg.service(all);
} }