feat(relays): layed the foundations for the relay runtime manager
This commit is contained in:
parent
4acdee0c18
commit
1d1f4896a4
|
@ -6,9 +6,10 @@ use log::info;
|
||||||
mod endpoints;
|
mod endpoints;
|
||||||
|
|
||||||
pub async fn start(config: &Config, backend: Backend) -> Result<()> {
|
pub async fn start(config: &Config, backend: Backend) -> Result<()> {
|
||||||
|
let data = web::Data::new(backend);
|
||||||
let server = HttpServer::new(move || {
|
let server = HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(web::Data::new(backend.clone()))
|
.app_data(data.clone())
|
||||||
.service(endpoints::account::register)
|
.service(endpoints::account::register)
|
||||||
.service(endpoints::account::auth)
|
.service(endpoints::account::auth)
|
||||||
.service(endpoints::account::invite::new)
|
.service(endpoints::account::invite::new)
|
||||||
|
|
|
@ -16,3 +16,15 @@ pub struct UsersRow {
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub permissions: u16,
|
pub permissions: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RelaysRow {
|
||||||
|
pub id: String,
|
||||||
|
pub secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RelayIndexRow {
|
||||||
|
pub public_id: String,
|
||||||
|
pub public_key: [u8; 32],
|
||||||
|
pub auth: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ pub enum Error {
|
||||||
#[error("Permission denied: {0}")]
|
#[error("Permission denied: {0}")]
|
||||||
PermissionDenied(&'static str),
|
PermissionDenied(&'static str),
|
||||||
|
|
||||||
|
#[error("The given relay id cannot be mapped to a relay")]
|
||||||
|
RelayNotFound,
|
||||||
|
|
||||||
#[error("The given token is expired")]
|
#[error("The given token is expired")]
|
||||||
TokenExpired,
|
TokenExpired,
|
||||||
|
|
||||||
|
@ -37,6 +40,7 @@ impl Into<HttpResponse> for Error {
|
||||||
Error::AuthenticationFailure => HttpResponse::Unauthorized().json(body),
|
Error::AuthenticationFailure => HttpResponse::Unauthorized().json(body),
|
||||||
Error::InvalidToken => HttpResponse::Unauthorized().json(body),
|
Error::InvalidToken => HttpResponse::Unauthorized().json(body),
|
||||||
Error::PermissionDenied(_) => HttpResponse::Forbidden().json(body),
|
Error::PermissionDenied(_) => HttpResponse::Forbidden().json(body),
|
||||||
|
Error::RelayNotFound => HttpResponse::NotFound().json(body),
|
||||||
Error::TokenExpired => HttpResponse::Gone().json(body),
|
Error::TokenExpired => HttpResponse::Gone().json(body),
|
||||||
Error::UserNotFound => HttpResponse::NotFound().json(body),
|
Error::UserNotFound => HttpResponse::NotFound().json(body),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,17 @@ mod relay;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::{backend::relay::Relay, config::Config};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use log::info;
|
use log::info;
|
||||||
use sqlx::MySqlPool;
|
use sqlx::MySqlPool;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
pub pool: MySqlPool,
|
pub pool: MySqlPool,
|
||||||
|
pub relays: HashMap<Uuid, Relay>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
@ -59,6 +62,9 @@ impl Backend {
|
||||||
|
|
||||||
info!("Backend initialized");
|
info!("Backend initialized");
|
||||||
|
|
||||||
Ok(Self { pool })
|
Ok(Self {
|
||||||
|
pool,
|
||||||
|
relays: HashMap::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,37 @@
|
||||||
use crate::backend::{error::Error, user::IntoUser, Backend};
|
use crate::backend::{
|
||||||
|
db_structures::{RelayIndexRow, RelaysRow},
|
||||||
|
error::Error,
|
||||||
|
user::IntoUser,
|
||||||
|
Backend,
|
||||||
|
};
|
||||||
|
use anyhow::{bail, Result};
|
||||||
use argon2::{
|
use argon2::{
|
||||||
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
|
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
|
||||||
Argon2,
|
Argon2,
|
||||||
};
|
};
|
||||||
use rand::distributions::DistString;
|
use rand::distributions::DistString;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct EncryptedMessage {
|
||||||
|
sender: Uuid,
|
||||||
|
body: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UserIndex {
|
||||||
|
public_key: [u8; 32],
|
||||||
|
name: String,
|
||||||
|
messages: VecDeque<EncryptedMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Relay {
|
||||||
|
user_index: HashMap<Uuid, UserIndex>,
|
||||||
|
user_map: HashMap<Uuid, Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
/// Creates the structures for a new relay
|
/// Creates the structures for a new relay
|
||||||
pub async fn create_relay(
|
pub async fn create_relay(
|
||||||
|
@ -38,7 +64,7 @@ impl Backend {
|
||||||
sqlx::query(&format!(
|
sqlx::query(&format!(
|
||||||
"CREATE TABLE RelayIndex_{} (
|
"CREATE TABLE RelayIndex_{} (
|
||||||
public_id UUID NOT NULL PRIMARY KEY,
|
public_id UUID NOT NULL PRIMARY KEY,
|
||||||
public_key BLOB(4096) NOT NULL,
|
public_key BINARY(32) NOT NULL,
|
||||||
auth VARCHAR(128) NOT NULL,
|
auth VARCHAR(128) NOT NULL,
|
||||||
name VARCHAR(32)
|
name VARCHAR(32)
|
||||||
);",
|
);",
|
||||||
|
@ -49,4 +75,36 @@ impl Backend {
|
||||||
|
|
||||||
Ok(Ok((relay_id, secret)))
|
Ok(Ok((relay_id, secret)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_relay(&mut self, relay_id: Uuid) -> Result<Result<&Relay, Error>> {
|
||||||
|
// can't use early return pattern, because of the borrow checker :/
|
||||||
|
if self.relays.get(&relay_id).is_none() {
|
||||||
|
match sqlx::query_as!(
|
||||||
|
RelaysRow,
|
||||||
|
r#"SELECT * FROM Relays WHERE id = ? LIMIT 1;"#,
|
||||||
|
relay_id.as_bytes().as_slice()
|
||||||
|
)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Err(sqlx::Error::RowNotFound) => return Ok(Err(Error::RelayNotFound)),
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
Ok(_) => {
|
||||||
|
// the hashmaps will be filled, as soon, as clients subscribe to the relay
|
||||||
|
let relay = Relay {
|
||||||
|
user_index: HashMap::new(),
|
||||||
|
user_map: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.relays.insert(relay_id, relay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(relay) = self.relays.get(&relay_id) {
|
||||||
|
Ok(Ok(relay))
|
||||||
|
} else {
|
||||||
|
bail!("!!! This should never happen !!! relay not found in runtime manager, even tho it was there before.")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue