From 8c8660597c8c4a684d579ccaa54bd042842ba542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Tue, 8 Aug 2023 20:45:29 +0200 Subject: [PATCH] reject if app already connected --- sdk/apps/base/src/app.test.ts | 2 +- sdk/apps/base/src/app.ts | 5 ++++ sdk/bindings/AlreadyConnected.ts | 3 +++ sdk/bindings/ServerToApp.ts | 3 ++- server/bindings/AlreadyConnected.ts | 3 +++ server/bindings/InitializeResponse.ts | 7 +---- server/bindings/ServerToApp.ts | 3 ++- server/src/app/app_handler.rs | 26 ++++++++++++++++--- .../structs/app_messages/already_connected.rs | 9 +++++++ .../src/structs/app_messages/app_messages.rs | 2 ++ server/src/structs/app_messages/mod.rs | 1 + 11 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 sdk/bindings/AlreadyConnected.ts create mode 100644 server/bindings/AlreadyConnected.ts create mode 100644 server/src/structs/app_messages/already_connected.rs diff --git a/sdk/apps/base/src/app.test.ts b/sdk/apps/base/src/app.test.ts index e344414c..999ffec1 100644 --- a/sdk/apps/base/src/app.test.ts +++ b/sdk/apps/base/src/app.test.ts @@ -52,7 +52,7 @@ describe('Base App tests', () => { assert(baseApp2.sessionId == sessionId) }) test('#on("userConnected")', async () => { - const baseApp = await BaseApp.build(testAppBaseInitialize) + const baseApp = await BaseApp.build({ ...testAppBaseInitialize, persistent: false }) expect(baseApp).toBeDefined() assert(baseApp.sessionId !== '') const userConnectedFn = vi.fn() diff --git a/sdk/apps/base/src/app.ts b/sdk/apps/base/src/app.ts index 0c89ec0b..3c77fcb3 100644 --- a/sdk/apps/base/src/app.ts +++ b/sdk/apps/base/src/app.ts @@ -100,6 +100,11 @@ export class BaseApp extends EventEmitter { case 'UserConnectedEvent': { baseApp.connectedPublicKeys = response.publicKeys baseApp.emit('userConnected', response) + break + } + case 'AlreadyConnected': { + reject(new Error('Already connected')) + break } } } diff --git a/sdk/bindings/AlreadyConnected.ts b/sdk/bindings/AlreadyConnected.ts new file mode 100644 index 00000000..3963a567 --- /dev/null +++ b/sdk/bindings/AlreadyConnected.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export interface AlreadyConnected { sessionId: string, } \ No newline at end of file diff --git a/sdk/bindings/ServerToApp.ts b/sdk/bindings/ServerToApp.ts index aba11a59..033e040f 100644 --- a/sdk/bindings/ServerToApp.ts +++ b/sdk/bindings/ServerToApp.ts @@ -1,9 +1,10 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AckMessage } from "./AckMessage"; +import type { AlreadyConnected } from "./AlreadyConnected"; import type { ErrorMessage } from "./ErrorMessage"; import type { InitializeResponse } from "./InitializeResponse"; import type { ResponsePayload } from "./ResponsePayload"; import type { UserConnectedEvent } from "./UserConnectedEvent"; import type { UserDisconnectedEvent } from "./UserDisconnectedEvent"; -export type ServerToApp = { type: "InitializeResponse" } & InitializeResponse | { type: "UserConnectedEvent" } & UserConnectedEvent | { type: "UserDisconnectedEvent" } & UserDisconnectedEvent | { type: "ResponsePayload" } & ResponsePayload | { type: "ErrorMessage" } & ErrorMessage | { type: "AckMessage" } & AckMessage; \ No newline at end of file +export type ServerToApp = { type: "InitializeResponse" } & InitializeResponse | { type: "UserConnectedEvent" } & UserConnectedEvent | { type: "UserDisconnectedEvent" } & UserDisconnectedEvent | { type: "ResponsePayload" } & ResponsePayload | { type: "ErrorMessage" } & ErrorMessage | { type: "AckMessage" } & AckMessage | { type: "AlreadyConnected" } & AlreadyConnected; \ No newline at end of file diff --git a/server/bindings/AlreadyConnected.ts b/server/bindings/AlreadyConnected.ts new file mode 100644 index 00000000..3963a567 --- /dev/null +++ b/server/bindings/AlreadyConnected.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export interface AlreadyConnected { sessionId: string, } \ No newline at end of file diff --git a/server/bindings/InitializeResponse.ts b/server/bindings/InitializeResponse.ts index 31f5acd4..d583bd32 100644 --- a/server/bindings/InitializeResponse.ts +++ b/server/bindings/InitializeResponse.ts @@ -1,8 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export interface InitializeResponse { - responseId: string - sessionId: string - createdNew: boolean - publicKeys: Array -} +export interface InitializeResponse { responseId: string, sessionId: string, createdNew: boolean, publicKeys: Array, } \ No newline at end of file diff --git a/server/bindings/ServerToApp.ts b/server/bindings/ServerToApp.ts index aba11a59..033e040f 100644 --- a/server/bindings/ServerToApp.ts +++ b/server/bindings/ServerToApp.ts @@ -1,9 +1,10 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AckMessage } from "./AckMessage"; +import type { AlreadyConnected } from "./AlreadyConnected"; import type { ErrorMessage } from "./ErrorMessage"; import type { InitializeResponse } from "./InitializeResponse"; import type { ResponsePayload } from "./ResponsePayload"; import type { UserConnectedEvent } from "./UserConnectedEvent"; import type { UserDisconnectedEvent } from "./UserDisconnectedEvent"; -export type ServerToApp = { type: "InitializeResponse" } & InitializeResponse | { type: "UserConnectedEvent" } & UserConnectedEvent | { type: "UserDisconnectedEvent" } & UserDisconnectedEvent | { type: "ResponsePayload" } & ResponsePayload | { type: "ErrorMessage" } & ErrorMessage | { type: "AckMessage" } & AckMessage; \ No newline at end of file +export type ServerToApp = { type: "InitializeResponse" } & InitializeResponse | { type: "UserConnectedEvent" } & UserConnectedEvent | { type: "UserDisconnectedEvent" } & UserDisconnectedEvent | { type: "ResponsePayload" } & ResponsePayload | { type: "ErrorMessage" } & ErrorMessage | { type: "AckMessage" } & AckMessage | { type: "AlreadyConnected" } & AlreadyConnected; \ No newline at end of file diff --git a/server/src/app/app_handler.rs b/server/src/app/app_handler.rs index 7924fbf5..623550f6 100644 --- a/server/src/app/app_handler.rs +++ b/server/src/app/app_handler.rs @@ -7,12 +7,14 @@ use axum::{ }, response::Response, }; -use futures::StreamExt; +use futures::{SinkExt, StreamExt}; +use log::warn; use crate::{ state::{ClientSockets, ClientToSessions, ModifySession, SendToClient, Sessions}, structs::{ app_messages::{ + already_connected::AlreadyConnected, app_messages::{AppToServer, ServerToApp}, initialize::InitializeResponse, }, @@ -45,7 +47,7 @@ pub async fn app_handler( client_sockets: ClientSockets, client_to_sessions: ClientToSessions, ) { - let (sender, mut receiver) = socket.split(); + let (mut sender, mut receiver) = socket.split(); // Handle the new app connection here // Wait for initialize message let session_id = loop { @@ -85,8 +87,24 @@ pub async fn app_handler( let mut sessions = sessions.write().await; match sessions.get_mut(session_id.as_str()) { Some(mut session) => { - // Close previous app socket - session.close_app_socket().await; + // Do not allow to connect to the same session twice + if session.app_state.app_socket.is_some() { + warn!("App tried to connect to the same session twice"); + let response = + ServerToApp::AlreadyConnected(AlreadyConnected { + session_id: session_id.clone(), + }); + sender + .send(Message::Text( + serde_json::to_string(&response) + .expect("Serialization should work"), + )) + .await + .unwrap_or_default(); + sender.close().await.unwrap_or_default(); + return; + } + session.update_status(SessionStatus::AppConnected); session.app_state = AppState { metadata: init_data.app_metadata, diff --git a/server/src/structs/app_messages/already_connected.rs b/server/src/structs/app_messages/already_connected.rs new file mode 100644 index 00000000..b89e2c99 --- /dev/null +++ b/server/src/structs/app_messages/already_connected.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, TS)] +#[ts(export)] +pub struct AlreadyConnected { + #[serde(rename = "sessionId")] + pub session_id: String, +} diff --git a/server/src/structs/app_messages/app_messages.rs b/server/src/structs/app_messages/app_messages.rs index 66db27b8..e51dd031 100644 --- a/server/src/structs/app_messages/app_messages.rs +++ b/server/src/structs/app_messages/app_messages.rs @@ -4,6 +4,7 @@ use ts_rs::TS; use crate::structs::common::{AckMessage, ErrorMessage}; use super::{ + already_connected::AlreadyConnected, initialize::{InitializeRequest, InitializeResponse}, payload::{RequestPayload, ResponsePayload}, user_connected_event::UserConnectedEvent, @@ -27,4 +28,5 @@ pub enum ServerToApp { ResponsePayload(ResponsePayload), ErrorMessage(ErrorMessage), AckMessage(AckMessage), + AlreadyConnected(AlreadyConnected), } diff --git a/server/src/structs/app_messages/mod.rs b/server/src/structs/app_messages/mod.rs index c0ede3b0..615c1030 100644 --- a/server/src/structs/app_messages/mod.rs +++ b/server/src/structs/app_messages/mod.rs @@ -1,3 +1,4 @@ +pub mod already_connected; pub mod app_messages; pub mod initialize; pub mod payload;