mirror of
https://github.com/Drop-OSS/dropbreak.git
synced 2026-07-18 09:57:53 -04:00
Add extensive example
This commit is contained in:
@@ -32,9 +32,16 @@ version = "0.7"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "0.2.1"
|
||||
rocket = "0.3.3"
|
||||
rocket_codegen = "0.3.3"
|
||||
serde_derive = "1"
|
||||
tempfile = "2.1"
|
||||
|
||||
[dev-dependencies.rocket_contrib]
|
||||
version = "0.3.3"
|
||||
default-features = false
|
||||
features = ["handlebars_templates"]
|
||||
|
||||
[features]
|
||||
bin = ["bincode", "base64", "error-chain"]
|
||||
yaml = ["serde_yaml"]
|
||||
|
||||
+2
-4
@@ -17,8 +17,7 @@ struct Person {
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rustbreak::Container;
|
||||
let db = Database::<Person, String>::from_path("test.yaml").unwrap();
|
||||
let db = Database::<HashMap<String, Person>>::from_path(HashMap::new(), "test.yaml").unwrap();
|
||||
|
||||
println!("Writing to Database");
|
||||
db.write(|db| {
|
||||
@@ -30,8 +29,7 @@ fn main() {
|
||||
name: String::from("Fred Johnson"),
|
||||
country: Country::UnitedKingdom
|
||||
});
|
||||
let map : &HashMap<_, _> = db.borrow();
|
||||
println!("Values: \n{:#?}", map.values());
|
||||
println!("Values: \n{:#?}", db.values());
|
||||
}).unwrap();
|
||||
|
||||
println!("Syncing Database");
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rustbreak;
|
||||
extern crate rocket;
|
||||
extern crate rocket_contrib;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
|
||||
use rocket::{State, Outcome};
|
||||
use rocket::http::{Cookies, Cookie};
|
||||
use rocket::request::{self, Request, FromRequest, Form};
|
||||
use rocket::response::Redirect;
|
||||
use rocket_contrib::Template;
|
||||
use rustbreak::Database;
|
||||
use rustbreak::deser::Ron;
|
||||
|
||||
// We create a type alias so that we always associate the same types to it
|
||||
type DB = Database<ServerData, Ron, File>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
struct Paste {
|
||||
user: String,
|
||||
body: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, FromForm)]
|
||||
struct NewPaste {
|
||||
body: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, FromForm)]
|
||||
struct User {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
impl <'a, 'r> FromRequest<'a, 'r> for User {
|
||||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<User, ()> {
|
||||
let mut cookies = request.cookies();
|
||||
let db = request.guard::<State<DB>>()?;
|
||||
match cookies.get_private("user_id") {
|
||||
Some(cookie) => {
|
||||
let mut outcome = Outcome::Forward(());
|
||||
let _ = db.read(|db| {
|
||||
if db.users.contains_key(cookie.value()) {
|
||||
outcome = Outcome::Success(db.users.get(cookie.value()).unwrap().clone());
|
||||
}
|
||||
});
|
||||
return outcome;
|
||||
}
|
||||
None => return Outcome::Forward(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
struct ServerData {
|
||||
pastes: Vec<Paste>,
|
||||
users: HashMap<String, User>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct TemplateData {
|
||||
pastes: Vec<Paste>,
|
||||
logged_in: bool,
|
||||
user: String
|
||||
}
|
||||
|
||||
|
||||
// Routing
|
||||
|
||||
#[get("/")]
|
||||
fn index(db: State<DB>, user: Option<User>) -> Template {
|
||||
let mut data = TemplateData {
|
||||
logged_in: user.is_some(),
|
||||
user: user.map(|u| u.username).unwrap_or_else(|| String::new()),
|
||||
pastes: vec![],
|
||||
};
|
||||
let _ = db.read(|db| {
|
||||
data.pastes = db.pastes.clone();
|
||||
});
|
||||
|
||||
return Template::render("index", &data);
|
||||
}
|
||||
|
||||
#[post("/register", data = "<req_user>")]
|
||||
fn post_register(db: State<DB>, req_user: Form<User>, mut cookies: Cookies) -> Redirect {
|
||||
let user = req_user.into_inner();
|
||||
let _ = db.write(|db| {
|
||||
if db.users.contains_key(&user.username) {
|
||||
return;
|
||||
}
|
||||
db.users.insert(user.username.clone(), user.clone());
|
||||
cookies.add_private(
|
||||
Cookie::build("user_id", user.username.clone()).http_only(true).finish()
|
||||
);
|
||||
});
|
||||
let _ = db.sync();
|
||||
|
||||
Redirect::to("/")
|
||||
}
|
||||
|
||||
#[post("/login", data = "<req_user>")]
|
||||
fn post_login(db: State<DB>, req_user: Form<User>, mut cookies: Cookies) -> Redirect {
|
||||
let user = req_user.into_inner();
|
||||
let _ = db.read(|db| {
|
||||
match db.users.get(&user.username) {
|
||||
Some(u) => {
|
||||
if u.password == user.password {
|
||||
cookies.add_private(
|
||||
Cookie::build("user_id", user.username.clone()).http_only(true).finish()
|
||||
);
|
||||
}
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
});
|
||||
|
||||
Redirect::to("/")
|
||||
}
|
||||
|
||||
#[post("/paste", data = "<paste>")]
|
||||
fn post_paste(db: State<DB>, user: User, paste: Form<NewPaste>) -> Redirect {
|
||||
let body : String = paste.into_inner().body.clone();
|
||||
let _ = db.write(|db| {
|
||||
let paste = Paste {
|
||||
body: body,
|
||||
user: user.username.clone(),
|
||||
};
|
||||
db.pastes.push(paste);
|
||||
});
|
||||
let _ = db.sync();
|
||||
|
||||
Redirect::to("/")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let db : DB = Database::from_path(ServerData {
|
||||
pastes: vec![],
|
||||
users: HashMap::new(),
|
||||
}, "server.ron").unwrap();
|
||||
let _ = db.reload();
|
||||
|
||||
|
||||
rocket::ignite()
|
||||
.mount("/", routes![index, post_login, post_paste, post_register])
|
||||
.attach(Template::fairing())
|
||||
.manage(db)
|
||||
.launch();
|
||||
}
|
||||
+37
-151
@@ -28,14 +28,13 @@
|
||||
//!
|
||||
//! At its core, Rustbreak is an attempt at making a configurable key-value store Database.
|
||||
//! It features the possibility of:
|
||||
//!
|
||||
//! - Choosing what kind of Data is stored in it
|
||||
//! - What kind of Container is storing it
|
||||
//! - Which kind of Serialization is used for persistence
|
||||
//! - Which kind of persistence is used
|
||||
//!
|
||||
//! Per default these options are used:
|
||||
//! - The Container is a HashMap<String>, leaving you the choice what you want to store in it, and
|
||||
//! can access it with a String key.
|
||||
//!
|
||||
//! - The Serialization is [Ron][ron], a familiar notation for Rust
|
||||
//! - The persistence is in-memory, allowing for quick prototyping
|
||||
//!
|
||||
@@ -47,12 +46,13 @@
|
||||
//! ## Quickstart
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use std::collections::HashMap;
|
||||
//! use rustbreak::Database;
|
||||
//!
|
||||
//! let db = Database::<String, String>::memory();
|
||||
//! let db = Database::<HashMap<String, String>>::memory(HashMap::new());
|
||||
//!
|
||||
//! println!("Writing to Database");
|
||||
//! db.write(|mut db| {
|
||||
//! db.write(|db| {
|
||||
//! db.insert("hello".into(), String::from("world"));
|
||||
//! db.insert("foo".into(), String::from("bar"));
|
||||
//! });
|
||||
@@ -66,7 +66,6 @@
|
||||
//!
|
||||
//! [daybreak]:https://propublica.github.io/daybreak
|
||||
//! [examples]: https://github.com/TheNeikos/rustbreak/tree/master/examples
|
||||
//! [examples]: https://github.com/TheNeikos/rustbreak/
|
||||
//! [ron]: https://github.com/ron-rs/ron
|
||||
|
||||
|
||||
@@ -86,14 +85,11 @@ mod backend;
|
||||
/// Different serialization and deserialization methods one can use
|
||||
pub mod deser;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{OpenOptions, File};
|
||||
use std::path::Path;
|
||||
use std::io::{Seek, SeekFrom, Read, Write};
|
||||
use std::sync::{Mutex, RwLock};
|
||||
use std::hash::Hash;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
@@ -103,125 +99,75 @@ pub use backend::Resizable;
|
||||
use error::{BreakResult, BreakError};
|
||||
use deser::{DeSerializer, Ron};
|
||||
|
||||
/// A container is a Key/Value storage
|
||||
pub trait Container<K: Hash + Eq + Debug, V> : Debug {
|
||||
/// Insert the value at the given key
|
||||
///
|
||||
/// Returns optionally an existing value that was replaced
|
||||
fn insert<T: Into<K>>(&mut self, key: T, value: V) -> Option<V>;
|
||||
|
||||
/// Removes the given value from the Container
|
||||
fn remove<T: AsRef<K>>(&mut self, key: T) -> Option<V>;
|
||||
|
||||
/// Borrows the given value from the Container
|
||||
fn get<T: AsRef<K>>(&self, key: T) -> Option<&V>;
|
||||
|
||||
/// Gets the underlying storage container mutably
|
||||
fn borrow_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
/// Gets the underlying storage container
|
||||
fn borrow(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Debug, K: Hash + Eq + Debug> Container<K, V> for HashMap<K, V> {
|
||||
fn insert<T: Into<K>>(&mut self, key: T, value: V) -> Option<V> {
|
||||
self.insert(key.into(), value)
|
||||
}
|
||||
fn remove<T: AsRef<K>>(&mut self, key: T) -> Option<V> {
|
||||
self.remove(key.as_ref())
|
||||
}
|
||||
fn get<T: AsRef<K>>(&self, key: T) -> Option<&V> {
|
||||
self.get(key.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The Central Database to RustBreak
|
||||
///
|
||||
/// It has 5 Type Generics:
|
||||
///
|
||||
/// - V: Is the Data, you must specify this (usually inferred by the compiler)
|
||||
/// - K: Is the Key, you must specify this (usually inferred by the compiler)
|
||||
/// - C: Is the backing Container, per default HashMap<String, D>
|
||||
/// - S: The Serializer/Deserializer or short DeSer. Per default `deser::Ron` is used
|
||||
/// - F: The storage backend. Per default it is in memory, but can be easily used with a file
|
||||
#[derive(Debug)]
|
||||
pub struct Database<V, K = String, C = HashMap<K, V>, S = Ron, F = RWVec>
|
||||
pub struct Database<V, S = Ron, F = RWVec>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
S: DeSerializer<V> + Sync + Send + Debug,
|
||||
F: Write + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
backing: Mutex<F>,
|
||||
data: RwLock<C>,
|
||||
data: RwLock<V>,
|
||||
deser: S,
|
||||
data_type: PhantomData<V>,
|
||||
key_type: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<V, K> Database<V, K, HashMap<K, V>>
|
||||
impl<V> Database<V>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
{
|
||||
/// Constructs a `Database` with in-memory Storage
|
||||
pub fn memory() -> Database<V, K, HashMap<K, V>, Ron, RWVec>
|
||||
pub fn memory(initial: V) -> Database<V, Ron, RWVec>
|
||||
{
|
||||
Database {
|
||||
backing: Mutex::new(RWVec::new()),
|
||||
data: RwLock::new(HashMap::new()),
|
||||
data: RwLock::new(initial),
|
||||
deser: Ron,
|
||||
data_type: PhantomData,
|
||||
key_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Database<V, K, HashMap<K, V>>
|
||||
impl<V> Database<V>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
{
|
||||
/// Constructs a `Database` with file-backed storage
|
||||
pub fn from_file(file: File) -> Database<V, K, HashMap<K, V>, Ron, File> {
|
||||
pub fn from_file(initial: V, file: File) -> Database<V, Ron, File> {
|
||||
Database {
|
||||
backing: Mutex::new(file),
|
||||
data: RwLock::new(HashMap::new()),
|
||||
data: RwLock::new(initial),
|
||||
deser: Ron,
|
||||
data_type: PhantomData,
|
||||
key_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a `Database` with file-backed storage from a given path
|
||||
pub fn from_path<P: AsRef<Path>>(path: P)
|
||||
-> BreakResult<Database<V, K, HashMap<K, V>, Ron, File>,
|
||||
<Ron as DeSerializer<K>>::SerError, <Ron as DeSerializer<K>>::DeError> {
|
||||
pub fn from_path<P: AsRef<Path>>(initial: V, path: P) -> BreakResult<Database<V, Ron, File>,
|
||||
<Ron as DeSerializer<V>>::SerError, <Ron as DeSerializer<V>>::DeError>
|
||||
{
|
||||
let file = OpenOptions::new().read(true).write(true).create(true).open(path)?;
|
||||
Ok(Self::from_file(file))
|
||||
Ok(Self::from_file(initial, file))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
impl<V, S, F> Database<V, S, F>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
S: DeSerializer<V> + Sync + Send + Debug,
|
||||
F: Write + Seek + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
/// Write locks the database and gives you write access to the underlying `Container`
|
||||
pub fn write<T>(&self, mut task: T)
|
||||
-> BreakResult<(), <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
where T: FnMut(&mut C)
|
||||
pub fn write<T>(&self, task: T)
|
||||
-> BreakResult<(), <S as DeSerializer<V>>::SerError, <S as DeSerializer<V>>::DeError>
|
||||
where T: FnOnce(&mut V)
|
||||
{
|
||||
let mut lock = self.data.write()?;
|
||||
task(&mut lock);
|
||||
@@ -234,7 +180,7 @@ impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
/// You __have__ to call this method yourself! Per default Rustbreak buffers everything
|
||||
/// in-memory and lets you decide when to write
|
||||
pub fn sync(&self)
|
||||
-> BreakResult<(), <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
-> BreakResult<(), <S as DeSerializer<V>>::SerError, <S as DeSerializer<V>>::DeError>
|
||||
{
|
||||
let mut backing = self.backing.lock()?;
|
||||
let data = self.data.read()?;
|
||||
@@ -253,7 +199,7 @@ impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
///
|
||||
/// This is useful to call at startup, or your Database might be empty!
|
||||
pub fn reload(&self)
|
||||
-> BreakResult<(), <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
-> BreakResult<(), <S as DeSerializer<V>>::SerError, <S as DeSerializer<V>>::DeError>
|
||||
{
|
||||
let mut backing = self.backing.lock()?;
|
||||
let mut data = self.data.write()?;
|
||||
@@ -269,86 +215,53 @@ impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
}
|
||||
|
||||
|
||||
impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
impl<V, S, F> Database<V, S, F>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
S: DeSerializer<V> + Sync + Send + Debug,
|
||||
F: Write + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
/// Read locks the database and gives you read access to the underlying `Container`
|
||||
pub fn read<T>(&self, mut task: T)
|
||||
-> BreakResult<(), <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
where T: FnMut(&C)
|
||||
pub fn read<T>(&self, task: T)
|
||||
-> BreakResult<(), <S as DeSerializer<V>>::SerError, <S as DeSerializer<V>>::DeError>
|
||||
where T: FnOnce(&V)
|
||||
{
|
||||
let lock = self.data.read()?;
|
||||
task(&lock);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Directly inserts a given piece of data into the Database
|
||||
pub fn insert<T: Into<K>>(&self, key: T, data: V)
|
||||
-> BreakResult<(), <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
{
|
||||
let mut lock = self.data.write()?;
|
||||
lock.insert(key, data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Directly removes a given piece of data from the Database
|
||||
pub fn remove<KK: AsRef<K>>(&self, key: KK)
|
||||
-> BreakResult<Option<V>, <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
{
|
||||
let mut lock = self.data.write()?;
|
||||
Ok(lock.remove(key))
|
||||
}
|
||||
|
||||
/// Directly removes a given piece of data from the Database
|
||||
pub fn get<KK: AsRef<K>>(&self, key: KK)
|
||||
-> BreakResult<Option<V>, <S as DeSerializer<C>>::SerError, <S as DeSerializer<C>>::DeError>
|
||||
{
|
||||
let lock = self.data.read()?;
|
||||
Ok(lock.get(key).cloned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
impl<V, S, F> Database<V, S, F>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
S: DeSerializer<V> + Sync + Send + Debug,
|
||||
F: Write + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
/// Exchanges a given deserialization method with another
|
||||
pub fn with_deser<T>(self, deser: T) -> Database<V, K, C, T, F>
|
||||
pub fn with_deser<T>(self, deser: T) -> Database<V, T, F>
|
||||
where
|
||||
T: DeSerializer<C> + Sync + Send + Debug,
|
||||
T: DeSerializer<V> + Sync + Send + Debug,
|
||||
{
|
||||
Database {
|
||||
backing: self.backing,
|
||||
data: self.data,
|
||||
deser: deser,
|
||||
data_type: PhantomData,
|
||||
key_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
impl<V, S, F> Database<V, S, F>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
S: DeSerializer<V> + Sync + Send + Debug,
|
||||
F: Write + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
/// Exchanges a given backing method with another
|
||||
pub fn with_backing<T>(self, backing: T) -> Database<V, K, C, S, T>
|
||||
pub fn with_backing<T>(self, backing: T) -> Database<V, S, T>
|
||||
where
|
||||
T: Write + Resizable + Debug,
|
||||
for<'r> &'r mut T: Read
|
||||
@@ -357,33 +270,6 @@ impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
backing: Mutex::new(backing),
|
||||
data: self.data,
|
||||
deser: self.deser,
|
||||
data_type: PhantomData,
|
||||
key_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K, C, S, F> Database<V, K, C, S, F>
|
||||
where
|
||||
V: Serialize + DeserializeOwned + Debug + Clone,
|
||||
K: Serialize + DeserializeOwned + Debug + Hash + Eq + Clone,
|
||||
C: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<C> + Sync + Send + Debug,
|
||||
F: Write + Resizable + Debug,
|
||||
for<'r> &'r mut F: Read
|
||||
{
|
||||
/// Exchanges a given container method with another
|
||||
pub fn with_container<T>(self, data: T) -> Database<V, K, T, S, F>
|
||||
where
|
||||
T: Serialize + DeserializeOwned + Container<K, V> + Debug,
|
||||
S: DeSerializer<T> + DeSerializer<C> + Sync + Send + Debug,
|
||||
{
|
||||
Database {
|
||||
backing: self.backing,
|
||||
data: RwLock::new(data),
|
||||
deser: self.deser,
|
||||
data_type: PhantomData,
|
||||
key_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rustbreak Pastes</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{{#if logged_in }}
|
||||
<div class="container">
|
||||
<div>
|
||||
You are logged in as: <strong>{{user}}</strong>
|
||||
</div>
|
||||
<form action="/paste" method="post">
|
||||
<div class="field">
|
||||
<label class="label is-small">Name</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" name="body" row="4"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control is-small">
|
||||
<button class="button is-link is-small">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<form action="/login" method="post" class="column">
|
||||
<div class="field">
|
||||
<label class="label is-small">Name</label>
|
||||
<div class="control is-small">
|
||||
<input class="input is-small" type="text" placeholder="Username" name="username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label is-small">Password</label>
|
||||
<div class="control is-small">
|
||||
<input class="input is-small" type="password" placeholder="Username" name="password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control is-small">
|
||||
<button class="button is-link is-small">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form action="/register" method="post" class="column">
|
||||
<div class="field">
|
||||
<label class="label is-small">Name</label>
|
||||
<div class="control is-small">
|
||||
<input class="input is-small" type="text" placeholder="Username" name="username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label is-small">Password</label>
|
||||
<div class="control is-small">
|
||||
<input class="input is-small" type="password" placeholder="Username" name="password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control is-small">
|
||||
<button class="button is-small is-link">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="container">
|
||||
<h1 class="title">Pastes</h1>
|
||||
|
||||
{{#each pastes as |p| ~}}
|
||||
<div class="box">
|
||||
<article class="media">
|
||||
<div class="media-content">
|
||||
<p>
|
||||
<strong>{{p.user}}</strong><br>
|
||||
{{p.body}}
|
||||
<p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{{/each~}}
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="content has-text-centered">
|
||||
<p>
|
||||
Made with love in Germany — Created using Rocket, Handlebars and Rustbreak
|
||||
</p>
|
||||
<a href="https://bulma.io">
|
||||
<img src="https://bulma.io/images/made-with-bulma.png" alt="Made with Bulma" width="128" height="24">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user