Move the command invoker and the socket_manager into the app
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -5105,6 +5105,7 @@ dependencies = [
|
||||
"axum-test",
|
||||
"cool_asserts",
|
||||
"fail",
|
||||
"futures",
|
||||
"rusqlite",
|
||||
"rusqlite_migration",
|
||||
"serde",
|
||||
|
||||
@@ -51,6 +51,7 @@ cairo-rs = { version = "0.18" }
|
||||
chrono = { version = "0.4" }
|
||||
chrono-tz = { version = "0.8" }
|
||||
dimensioned = { version = "0.8", features = [ "serde" ] }
|
||||
futures = { version = "0.3" }
|
||||
gdk = { version = "0.7", package = "gdk4" }
|
||||
gio = { version = "0.18" }
|
||||
glib = { version = "0.18" }
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use futures::future::join_all;
|
||||
use visions_types::{CharacterId, GameId, GameMessage, UserId};
|
||||
|
||||
use crate::{
|
||||
AppData, Error, Fatal, socket_manager::OutgoingMessage, substrate::Substrate, types::User,
|
||||
};
|
||||
use crate::{Error, Fatal, substrate::Substrate};
|
||||
|
||||
mod card;
|
||||
pub use card::*;
|
||||
@@ -28,8 +25,8 @@ pub enum ResourceId {
|
||||
CharacterId(CharacterId),
|
||||
}
|
||||
|
||||
struct CommandContext<'a> {
|
||||
app: &'a Substrate,
|
||||
pub struct CommandContext<'a> {
|
||||
pub app: &'a Substrate,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -75,7 +72,7 @@ impl<A> From<Result<A, Error>> for CommandResult<A> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GrantedBy {
|
||||
pub enum GrantedBy {
|
||||
Admin,
|
||||
AuthenticatedUser(UserId),
|
||||
GameGm(GameId),
|
||||
@@ -86,179 +83,14 @@ enum GrantedBy {
|
||||
Anyone,
|
||||
}
|
||||
|
||||
struct Requirement {
|
||||
granted_by: GrantedBy,
|
||||
pub struct Requirement {
|
||||
pub granted_by: GrantedBy,
|
||||
}
|
||||
|
||||
trait Command<A>: Send + Sync + std::fmt::Debug {
|
||||
pub trait Command<A>: Send + Sync + std::fmt::Debug {
|
||||
fn requirements(&self) -> Vec<Requirement>;
|
||||
fn execute(
|
||||
&self,
|
||||
ctx: CommandContext,
|
||||
) -> impl Future<Output = Result<CommandResult<A>, Fatal>> + Send;
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub async fn invoke<T: Command<A>, A>(
|
||||
app: &AppData,
|
||||
command: T,
|
||||
user: Option<&User>,
|
||||
) -> Result<Result<A, Error>, Fatal> {
|
||||
eprintln!("invoking {:?}", command);
|
||||
let result = run_command(&app.substrate, command, user).await?;
|
||||
|
||||
match result.value {
|
||||
Ok(_) => eprintln!("\tsuccess"),
|
||||
Err(ref err) => eprintln!("\tfailure: {:?}", err),
|
||||
}
|
||||
|
||||
for (user_id, message) in result.messages.into_iter() {
|
||||
if let Err(error) = app
|
||||
.socket_manager
|
||||
.send(OutgoingMessage::SendToUser(
|
||||
user_id.clone(),
|
||||
message.clone(),
|
||||
))
|
||||
.await
|
||||
{
|
||||
eprintln!(
|
||||
"Error sending to user {:?} {:?}: {:?}",
|
||||
user_id, message, error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (game_id, message) in result.broadcast_messages.into_iter() {
|
||||
if let Err(error) = app
|
||||
.socket_manager
|
||||
.send(OutgoingMessage::BroadcastToGame(
|
||||
game_id.clone(),
|
||||
message.clone(),
|
||||
))
|
||||
.await
|
||||
{
|
||||
eprintln!(
|
||||
"Error sending to game {:?} {:?}: {:?}",
|
||||
game_id, message, error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result.value)
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub async fn run_command<T: Command<A>, A>(
|
||||
app: &Substrate,
|
||||
command: T,
|
||||
user: Option<&User>,
|
||||
) -> Result<CommandResult<A>, Fatal> {
|
||||
let permission_granted: Vec<bool> = join_all(
|
||||
command
|
||||
.requirements()
|
||||
.iter()
|
||||
.map(|req| Box::pin(permission_granted(app, req, user))),
|
||||
)
|
||||
.await;
|
||||
|
||||
if permission_granted.into_iter().any(|t| t) {
|
||||
Ok(command.execute(CommandContext { app }).await?)
|
||||
} else if user.is_some() {
|
||||
Ok(CommandResult::new(Err(Error::Forbidden)))
|
||||
} else {
|
||||
Ok(CommandResult::new(Err(Error::Unauthorized)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn permission_granted(app: &Substrate, req: &Requirement, user: Option<&User>) -> bool {
|
||||
match req.granted_by {
|
||||
GrantedBy::Admin => {
|
||||
if let Some(user) = user {
|
||||
user.admin
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::AuthenticatedUser(ref req_user) => {
|
||||
if let Some(auth) = user {
|
||||
auth.id == *req_user
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameGm(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
|
||||
if let Some(user) = user {
|
||||
game.gm == user.id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameParticipant(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
|
||||
if let Some(user) = user {
|
||||
game.contains_user(&user.id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameParticipantOrSpectator(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
eprintln!(
|
||||
"{:?} game open to spectators: {}",
|
||||
game.id, game.open_to_spectators
|
||||
);
|
||||
|
||||
if let Some(user) = user {
|
||||
if game.contains_user(&user.id) {
|
||||
true
|
||||
} else {
|
||||
game.open_to_spectators
|
||||
}
|
||||
} else {
|
||||
game.open_to_spectators
|
||||
}
|
||||
}
|
||||
GrantedBy::ResourceOwner(ref resource_id) => {
|
||||
let Some(user) = user else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match resource_id {
|
||||
ResourceId::CharacterId(character_id) => {
|
||||
let Ok(character) = app.charsheet(character_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
character.user_id == user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
GrantedBy::ResourceOwnerOrGameGm(ref resource_id) => {
|
||||
let Some(user) = user else {
|
||||
return false;
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"GrantedBy::ResourceOwnerOrGameGm: {:?} {:?}",
|
||||
user.id, resource_id
|
||||
);
|
||||
|
||||
match resource_id {
|
||||
ResourceId::CharacterId(character_id) => {
|
||||
let Ok(character) = app.charsheet(character_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
let Ok(game) = app.game(&character.game_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
game.gm == user.id || character.user_id == user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
GrantedBy::Anyone => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,13 @@ use webauthn_rs::prelude::*;
|
||||
|
||||
pub mod commands;
|
||||
pub mod database;
|
||||
pub mod socket_manager;
|
||||
pub mod substrate;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
pub use commands::{CreateInvitation, invoke, run_command};
|
||||
pub use commands::CreateInvitation;
|
||||
|
||||
use crate::{database::CannotCreate, socket_manager::SocketManager, substrate::Substrate};
|
||||
use crate::database::CannotCreate;
|
||||
|
||||
#[cfg(test)]
|
||||
mod commands_test;
|
||||
@@ -81,9 +80,3 @@ impl From<database::Fatal> for Fatal {
|
||||
Self(format!("{}", value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppData {
|
||||
pub substrate: Substrate,
|
||||
pub socket_manager: SocketManager,
|
||||
}
|
||||
|
||||
@@ -12,10 +12,7 @@ use std::{
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use tokio::sync::{
|
||||
RwLock,
|
||||
mpsc::{Receiver, Sender, channel},
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
use visions_types::*;
|
||||
use webauthn_rs::prelude::*;
|
||||
@@ -23,7 +20,7 @@ use webauthn_rs::prelude::*;
|
||||
use crate::{
|
||||
Error, Fatal, clone,
|
||||
database::{Database, DbHandle},
|
||||
types::{Password, SocketId, TabletopRow, User},
|
||||
types::{Password, TabletopRow, User},
|
||||
};
|
||||
|
||||
pub struct App_ {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use ring::{digest, rand::SecureRandom};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use visions_types::{AccountStatus, GameId, ImageId, SceneId, UserId, UserOverview, identifier};
|
||||
|
||||
identifier!(SocketId);
|
||||
use visions_types::{AccountStatus, GameId, ImageId, SceneId, UserId, UserOverview};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
|
||||
@@ -8,6 +8,7 @@ axum = { workspace = true }
|
||||
axum-test = { version = "17.3.0", features = ["ws"] }
|
||||
cool_asserts = "2.0.3"
|
||||
fail = "0.5"
|
||||
futures = { workspace = true }
|
||||
rusqlite = "0.38"
|
||||
rusqlite_migration = "2.4"
|
||||
serde = { workspace = true }
|
||||
|
||||
178
visions/server/src/executor.rs
Normal file
178
visions/server/src/executor.rs
Normal file
@@ -0,0 +1,178 @@
|
||||
use visions_core::{
|
||||
commands::{Command, CommandContext, CommandResult, GrantedBy, Requirement, ResourceId},
|
||||
substrate::Substrate,
|
||||
types::User,
|
||||
Error, Fatal,
|
||||
};
|
||||
|
||||
use crate::{socket_manager::OutgoingMessage, AppData};
|
||||
use futures::future::join_all;
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub async fn invoke<T: Command<A>, A>(
|
||||
app: &AppData,
|
||||
command: T,
|
||||
user: Option<&User>,
|
||||
) -> Result<Result<A, Error>, Fatal> {
|
||||
eprintln!("invoking {:?}", command);
|
||||
let result = run_command(&app, command, user).await?;
|
||||
|
||||
match result.value {
|
||||
Ok(_) => eprintln!("\tsuccess"),
|
||||
Err(ref err) => eprintln!("\tfailure: {:?}", err),
|
||||
}
|
||||
|
||||
for (user_id, message) in result.messages.into_iter() {
|
||||
if let Err(error) = app
|
||||
.socket_manager
|
||||
.send(OutgoingMessage::SendToUser(
|
||||
user_id.clone(),
|
||||
message.clone(),
|
||||
))
|
||||
.await
|
||||
{
|
||||
eprintln!(
|
||||
"Error sending to user {:?} {:?}: {:?}",
|
||||
user_id, message, error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (game_id, message) in result.broadcast_messages.into_iter() {
|
||||
if let Err(error) = app
|
||||
.socket_manager
|
||||
.send(OutgoingMessage::BroadcastToGame(
|
||||
game_id.clone(),
|
||||
message.clone(),
|
||||
))
|
||||
.await
|
||||
{
|
||||
eprintln!(
|
||||
"Error sending to game {:?} {:?}: {:?}",
|
||||
game_id, message, error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result.value)
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub async fn run_command<T: Command<A>, A>(
|
||||
app: &AppData,
|
||||
command: T,
|
||||
user: Option<&User>,
|
||||
) -> Result<CommandResult<A>, Fatal> {
|
||||
let permission_granted: Vec<bool> = join_all(
|
||||
command
|
||||
.requirements()
|
||||
.iter()
|
||||
.map(|req| Box::pin(permission_granted(&app.substrate, req, user))),
|
||||
)
|
||||
.await;
|
||||
|
||||
if permission_granted.into_iter().any(|t| t) {
|
||||
Ok(command
|
||||
.execute(CommandContext {
|
||||
app: &app.substrate,
|
||||
})
|
||||
.await?)
|
||||
} else if user.is_some() {
|
||||
Ok(CommandResult::new(Err(Error::Forbidden)))
|
||||
} else {
|
||||
Ok(CommandResult::new(Err(Error::Unauthorized)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn permission_granted(app: &Substrate, req: &Requirement, user: Option<&User>) -> bool {
|
||||
match req.granted_by {
|
||||
GrantedBy::Admin => {
|
||||
if let Some(user) = user {
|
||||
user.admin
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::AuthenticatedUser(ref req_user) => {
|
||||
if let Some(auth) = user {
|
||||
auth.id == *req_user
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameGm(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
|
||||
if let Some(user) = user {
|
||||
game.gm == user.id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameParticipant(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
|
||||
if let Some(user) = user {
|
||||
game.contains_user(&user.id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
GrantedBy::GameParticipantOrSpectator(ref game_id) => {
|
||||
let game = app.game(&game_id).await.unwrap().unwrap();
|
||||
eprintln!(
|
||||
"{:?} game open to spectators: {}",
|
||||
game.id, game.open_to_spectators
|
||||
);
|
||||
|
||||
if let Some(user) = user {
|
||||
if game.contains_user(&user.id) {
|
||||
true
|
||||
} else {
|
||||
game.open_to_spectators
|
||||
}
|
||||
} else {
|
||||
game.open_to_spectators
|
||||
}
|
||||
}
|
||||
GrantedBy::ResourceOwner(ref resource_id) => {
|
||||
let Some(user) = user else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match resource_id {
|
||||
ResourceId::CharacterId(character_id) => {
|
||||
let Ok(character) = app.charsheet(character_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
character.user_id == user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
GrantedBy::ResourceOwnerOrGameGm(ref resource_id) => {
|
||||
let Some(user) = user else {
|
||||
return false;
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"GrantedBy::ResourceOwnerOrGameGm: {:?} {:?}",
|
||||
user.id, resource_id
|
||||
);
|
||||
|
||||
match resource_id {
|
||||
ResourceId::CharacterId(character_id) => {
|
||||
let Ok(character) = app.charsheet(character_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
let Ok(game) = app.game(&character.game_id).await.unwrap() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
game.gm == user.id || character.user_id == user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
GrantedBy::Anyone => false,
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
use axum::{body::Body, extract::State, http::Response, Json};
|
||||
use visions_core::AppData;
|
||||
use visions_types::{
|
||||
FinishPasskeyAuthRequest, FinishRegisterPasskeyRequest, StartRegisterPasskeyRequest,
|
||||
};
|
||||
|
||||
use crate::handlers::http_adapter;
|
||||
use crate::{handlers::http_adapter, AppData};
|
||||
|
||||
pub async fn register_passkey_start(
|
||||
app: State<AppData>,
|
||||
|
||||
@@ -8,16 +8,15 @@ use axum::{
|
||||
use visions_core::{
|
||||
clone,
|
||||
commands::{CreateCard, ListCards},
|
||||
invoke, AppData,
|
||||
};
|
||||
use visions_types::{
|
||||
CardId, CardsFilter, CharacterId, CreateCardRequest, GameId, Location, UpdateCardRequest,
|
||||
};
|
||||
|
||||
use crate::{handlers::http_adapter, router::auth_required};
|
||||
use crate::{executor::invoke, handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn get_card(
|
||||
app: State<AppData>,
|
||||
_app: State<AppData>,
|
||||
_headers: HeaderMap,
|
||||
_params: Path<CardId>,
|
||||
) -> Response<Body> {
|
||||
|
||||
@@ -8,11 +8,10 @@ use axum::{
|
||||
use visions_core::{
|
||||
clone,
|
||||
commands::{CreateCharacter, GetCharacter, ListCharacters, UpdateCharacter},
|
||||
invoke, AppData,
|
||||
};
|
||||
use visions_types::*;
|
||||
|
||||
use crate::{handlers::http_adapter, router::auth_required};
|
||||
use crate::{executor::invoke, handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn get_self(app: State<AppData>, headers: HeaderMap) -> Response<Body> {
|
||||
auth_required(app, headers, |user| {
|
||||
|
||||
@@ -4,10 +4,10 @@ use axum::{
|
||||
http::{HeaderMap, Response},
|
||||
Json,
|
||||
};
|
||||
use visions_core::{clone, commands::ToggleOpenToSpectators, invoke, AppData, Error, Fatal};
|
||||
use visions_core::{clone, commands::ToggleOpenToSpectators, Error, Fatal};
|
||||
use visions_types::{CreateGameRequest, GameId, UserId};
|
||||
|
||||
use crate::{handlers::http_adapter, router::auth_required};
|
||||
use crate::{executor::invoke, handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn get_game(
|
||||
app: State<AppData>,
|
||||
|
||||
@@ -4,10 +4,10 @@ use axum::{
|
||||
http::{HeaderMap, Response},
|
||||
Json,
|
||||
};
|
||||
use visions_core::{clone, AppData};
|
||||
use visions_core::clone;
|
||||
use visions_types::*;
|
||||
|
||||
use crate::{handlers::http_adapter, router::auth_required};
|
||||
use crate::{handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn get_images(
|
||||
app: State<AppData>,
|
||||
@@ -18,7 +18,7 @@ pub async fn get_images(
|
||||
auth_required(
|
||||
app.clone(),
|
||||
headers,
|
||||
clone!((app, filter), move |user| {
|
||||
clone!((app, filter), move |_user| {
|
||||
clone!((app, filter), async move {
|
||||
http_adapter(app.substrate.images(filter)).await
|
||||
})
|
||||
|
||||
@@ -6,14 +6,11 @@ use axum::{
|
||||
};
|
||||
use visions_core::{
|
||||
clone,
|
||||
commands::{invoke, CreateInvitation, ListInvitations},
|
||||
AppData,
|
||||
commands::{CreateInvitation, ListInvitations},
|
||||
};
|
||||
use visions_types::{CreateInvitationRequest, InvitationId};
|
||||
|
||||
use crate::router::auth_required;
|
||||
|
||||
use super::http_adapter;
|
||||
use crate::{executor::invoke, handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn invitations(app: State<AppData>, headers: HeaderMap) -> Response<Body> {
|
||||
auth_required(app.clone(), headers, move |user| {
|
||||
|
||||
@@ -4,10 +4,10 @@ use axum::{
|
||||
http::{HeaderMap, Response},
|
||||
Json,
|
||||
};
|
||||
use visions_core::{clone, commands::SetScene, invoke, AppData};
|
||||
use visions_core::{clone, commands::SetScene};
|
||||
use visions_types::*;
|
||||
|
||||
use crate::{handlers::http_adapter, router::auth_required};
|
||||
use crate::{executor::invoke, handlers::http_adapter, router::auth_required, AppData};
|
||||
|
||||
pub async fn get_scenes(
|
||||
app: State<AppData>,
|
||||
|
||||
@@ -5,13 +5,14 @@ use axum::{
|
||||
response::IntoResponse,
|
||||
Json,
|
||||
};
|
||||
use visions_core::{clone, commands::GetTabletop, invoke, AppData};
|
||||
use visions_core::{clone, commands::GetTabletop};
|
||||
use visions_types::{GameId, SetTabletopImageRequest};
|
||||
|
||||
use crate::{
|
||||
executor::invoke,
|
||||
handlers::http_adapter,
|
||||
router::{auth_required, check_auth_headers},
|
||||
ApiError,
|
||||
ApiError, AppData,
|
||||
};
|
||||
|
||||
pub async fn get_tabletop(
|
||||
|
||||
@@ -4,12 +4,11 @@ use axum::{
|
||||
http::{HeaderMap, Response, StatusCode},
|
||||
Json,
|
||||
};
|
||||
use visions_core::AppData;
|
||||
use visions_types::CreateUserRequest;
|
||||
|
||||
use crate::{
|
||||
router::{auth_required, parse_session_header},
|
||||
ApiError,
|
||||
ApiError, AppData,
|
||||
};
|
||||
|
||||
use super::http_adapter;
|
||||
|
||||
@@ -3,9 +3,10 @@ use axum::extract::{
|
||||
WebSocketUpgrade,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use visions_core::{clone, Fatal};
|
||||
use visions_types::{GameMessage, GameRequest};
|
||||
|
||||
use visions_core::{clone, types::SocketId, AppData, Fatal};
|
||||
use crate::{socket_manager::SocketId, AppData};
|
||||
|
||||
pub async fn websocket_handler(ws: WebSocketUpgrade, app: AppData) -> axum::response::Response {
|
||||
ws.on_upgrade(clone!(app, move |socket| async {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
use thiserror::Error;
|
||||
use visions_core::{socket_manager::SocketManager, substrate::Substrate};
|
||||
use visions_core::substrate::Substrate;
|
||||
|
||||
use crate::socket_manager::SocketManager;
|
||||
|
||||
pub mod executor;
|
||||
pub mod handlers;
|
||||
pub mod router;
|
||||
pub mod socket_manager;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ApiError {
|
||||
@@ -13,3 +17,9 @@ pub enum ApiError {
|
||||
#[error("bad request")]
|
||||
BadRequest,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppData {
|
||||
pub substrate: Substrate,
|
||||
pub socket_manager: SocketManager,
|
||||
}
|
||||
|
||||
@@ -3,10 +3,8 @@ use std::path::PathBuf;
|
||||
use axum::Router;
|
||||
use tower_http::trace::{self, TraceLayer};
|
||||
use tracing::Level;
|
||||
use visions_core::{
|
||||
database::Database, socket_manager::SocketManager, substrate::Substrate, AppData,
|
||||
};
|
||||
use visions_server_lib::router::api_routes;
|
||||
use visions_core::{database::Database, substrate::Substrate};
|
||||
use visions_server_lib::{router::api_routes, socket_manager::SocketManager, AppData};
|
||||
use visions_types::SPAConfig;
|
||||
|
||||
#[tokio::main]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use axum::{
|
||||
extract::{Path, WebSocketUpgrade},
|
||||
extract::WebSocketUpgrade,
|
||||
http::{
|
||||
header::{AUTHORIZATION, CONTENT_TYPE},
|
||||
HeaderMap, HeaderValue, Method, StatusCode,
|
||||
@@ -11,10 +11,10 @@ use axum::{
|
||||
mod utils;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
pub use utils::*;
|
||||
use visions_core::{clone, substrate::Substrate, AppData};
|
||||
use visions_types::{CardId, SPAConfig};
|
||||
use visions_core::clone;
|
||||
use visions_types::SPAConfig;
|
||||
|
||||
use crate::handlers::*;
|
||||
use crate::{handlers::*, AppData};
|
||||
|
||||
pub fn api_routes(app: AppData, spa_config: SPAConfig) -> Router {
|
||||
Router::new()
|
||||
|
||||
@@ -7,10 +7,10 @@ use axum::{
|
||||
response::IntoResponse,
|
||||
Json,
|
||||
};
|
||||
use visions_core::{types::User, AppData};
|
||||
use visions_core::types::User;
|
||||
use visions_types::{AuthRequest, AuthResponse, SessionId};
|
||||
|
||||
use crate::{handlers::http_adapter, ApiError};
|
||||
use crate::{handlers::http_adapter, ApiError, AppData};
|
||||
|
||||
pub fn parse_session_header(headers: HeaderMap) -> Result<Option<SessionId>, ApiError> {
|
||||
match headers.get("Authorization") {
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
RwLock,
|
||||
mpsc::{Receiver, Sender, channel},
|
||||
};
|
||||
use visions_types::{GameId, GameMessage, GameRequest, SessionId, UserId};
|
||||
|
||||
use crate::{
|
||||
Fatal,
|
||||
substrate::Substrate,
|
||||
types::{SocketId, User},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
use visions_core::{substrate::Substrate, types::User, Fatal};
|
||||
use visions_types::{identifier, GameId, GameMessage, GameRequest, SessionId, UserId};
|
||||
|
||||
pub enum OutgoingMessage {
|
||||
SendToUser(UserId, GameMessage),
|
||||
BroadcastToGame(GameId, GameMessage),
|
||||
}
|
||||
|
||||
identifier!(SocketId);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Socket {
|
||||
pub id: SocketId,
|
||||
Reference in New Issue
Block a user