add global RwLock for SQLite
now tests pass
This commit is contained in:
parent
f611c5378d
commit
2893bbd595
25
src/main.rs
25
src/main.rs
|
@ -14,7 +14,6 @@ extern crate serde;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
extern crate scrypt;
|
extern crate scrypt;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[cfg(test)]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
mod schema;
|
mod schema;
|
||||||
|
@ -31,9 +30,33 @@ use rocket::Rocket;
|
||||||
use rocket::config::{Config, Environment, Value};
|
use rocket::config::{Config, Environment, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
embed_migrations!();
|
embed_migrations!();
|
||||||
|
|
||||||
|
// We need a global RwLock for SQLite
|
||||||
|
// This is unfortunate when we still use SQLite
|
||||||
|
// but should be mostly fine for our purpose
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref DB_LOCK: RwLock<()> = RwLock::new(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! lock_db_write {
|
||||||
|
() => {
|
||||||
|
crate::DB_LOCK.write()
|
||||||
|
.map_err(|_| "Cannot lock database for writing".into())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! lock_db_read {
|
||||||
|
() => {
|
||||||
|
crate::DB_LOCK.read()
|
||||||
|
.map_err(|_| "Cannot lock database for reading".into())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[database("db")]
|
#[database("db")]
|
||||||
pub struct DbConn(SqliteConnection);
|
pub struct DbConn(SqliteConnection);
|
||||||
|
|
||||||
|
|
38
src/user.rs
38
src/user.rs
|
@ -1,5 +1,6 @@
|
||||||
use crate::schema::users;
|
use crate::schema::users;
|
||||||
use crate::schema::users::dsl::*;
|
use crate::schema::users::dsl::*;
|
||||||
|
use crate::{lock_db_write, lock_db_read};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::sqlite::SqliteConnection;
|
use diesel::sqlite::SqliteConnection;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -15,6 +16,12 @@ impl UserOpError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<UserOpError> for &str {
|
||||||
|
fn into(self) -> UserOpError {
|
||||||
|
UserOpError::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Password should ALWAYS be hashed
|
// Password should ALWAYS be hashed
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Password(String);
|
pub struct Password(String);
|
||||||
|
@ -104,19 +111,21 @@ impl User {
|
||||||
|
|
||||||
match Self::find_user_by_email(db, &new_user.email) {
|
match Self::find_user_by_email(db, &new_user.email) {
|
||||||
Ok(_) => Err(UserOpError::new("User already registered")),
|
Ok(_) => Err(UserOpError::new("User already registered")),
|
||||||
Err(_) => diesel::insert_into(users::table)
|
Err(_) => lock_db_write!()
|
||||||
.values(user_hashed)
|
.and_then(|_| diesel::insert_into(users::table)
|
||||||
.execute(db)
|
.values(user_hashed)
|
||||||
.map(|_| ())
|
.execute(db)
|
||||||
.map_err(|_| UserOpError::new("Database error"))
|
.map(|_| ())
|
||||||
|
.map_err(|_| UserOpError::new("Database error")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_user_by_email(db: &SqliteConnection, user_email: &str) -> Result<User, UserOpError> {
|
pub fn find_user_by_email(db: &SqliteConnection, user_email: &str) -> Result<User, UserOpError> {
|
||||||
let mut results = users.filter(email.eq(user_email))
|
let mut results = lock_db_read!()
|
||||||
.limit(1)
|
.and_then(|_| users.filter(email.eq(user_email))
|
||||||
.load::<UserQuery>(db)
|
.limit(1)
|
||||||
.map_err(|_| UserOpError::new("Database error"))?;
|
.load::<UserQuery>(db)
|
||||||
|
.map_err(|_| UserOpError::new("Database error")))?;
|
||||||
if results.is_empty() {
|
if results.is_empty() {
|
||||||
Result::Err(UserOpError::new("No matching user found"))
|
Result::Err(UserOpError::new("No matching user found"))
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,11 +166,12 @@ impl User {
|
||||||
// Update database
|
// Update database
|
||||||
// TODO: Maybe we should revoke all JWTs somehow?
|
// TODO: Maybe we should revoke all JWTs somehow?
|
||||||
// maybe we can record when the user last changed?
|
// maybe we can record when the user last changed?
|
||||||
diesel::update(users.find(self.id))
|
lock_db_write!()
|
||||||
.set(password.eq::<String>(Password::new(new_passwd).into()))
|
.and_then(|_| diesel::update(users.find(self.id))
|
||||||
.execute(db)
|
.set(password.eq::<String>(Password::new(new_passwd).into()))
|
||||||
.map(|_| ())
|
.execute(db)
|
||||||
.map_err(|_| UserOpError::new("Database error"))
|
.map(|_| ())
|
||||||
|
.map_err(|_| UserOpError::new("Database error")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue