feat(relays): layed the foundations for the relay runtime manager

This commit is contained in:
antifallobst 2024-03-24 19:40:52 +01:00
parent 4acdee0c18
commit 1d1f4896a4
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
5 changed files with 87 additions and 6 deletions

View File

@ -6,9 +6,10 @@ use log::info;
mod endpoints;
pub async fn start(config: &Config, backend: Backend) -> Result<()> {
let data = web::Data::new(backend);
let server = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(backend.clone()))
.app_data(data.clone())
.service(endpoints::account::register)
.service(endpoints::account::auth)
.service(endpoints::account::invite::new)

View File

@ -16,3 +16,15 @@ pub struct UsersRow {
pub password: String,
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,
}

View File

@ -13,6 +13,9 @@ pub enum Error {
#[error("Permission denied: {0}")]
PermissionDenied(&'static str),
#[error("The given relay id cannot be mapped to a relay")]
RelayNotFound,
#[error("The given token is expired")]
TokenExpired,
@ -37,6 +40,7 @@ impl Into<HttpResponse> for Error {
Error::AuthenticationFailure => HttpResponse::Unauthorized().json(body),
Error::InvalidToken => HttpResponse::Unauthorized().json(body),
Error::PermissionDenied(_) => HttpResponse::Forbidden().json(body),
Error::RelayNotFound => HttpResponse::NotFound().json(body),
Error::TokenExpired => HttpResponse::Gone().json(body),
Error::UserNotFound => HttpResponse::NotFound().json(body),
}

View File

@ -5,14 +5,17 @@ mod relay;
mod tokens;
mod user;
use crate::config::Config;
use crate::{backend::relay::Relay, config::Config};
use anyhow::Result;
use log::info;
use sqlx::MySqlPool;
use std::collections::HashMap;
use uuid::Uuid;
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Backend {
pub pool: MySqlPool,
pub relays: HashMap<Uuid, Relay>,
}
impl Backend {
@ -59,6 +62,9 @@ impl Backend {
info!("Backend initialized");
Ok(Self { pool })
Ok(Self {
pool,
relays: HashMap::new(),
})
}
}

View File

@ -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::{
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
Argon2,
};
use rand::distributions::DistString;
use std::collections::{HashMap, VecDeque};
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 {
/// Creates the structures for a new relay
pub async fn create_relay(
@ -38,7 +64,7 @@ impl Backend {
sqlx::query(&format!(
"CREATE TABLE RelayIndex_{} (
public_id UUID NOT NULL PRIMARY KEY,
public_key BLOB(4096) NOT NULL,
public_key BINARY(32) NOT NULL,
auth VARCHAR(128) NOT NULL,
name VARCHAR(32)
);",
@ -49,4 +75,36 @@ impl Backend {
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.")
}
}
}