From e313f7f6ba7eac108c3c6c7ea83c060f3ba3e9eb Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 22 Jul 2025 10:12:29 -0700 Subject: [PATCH 1/4] Adding reject-client-connections doc from PR of docs repo. --- docs/docs/how-to/reject-client-connections.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/docs/how-to/reject-client-connections.md diff --git a/docs/docs/how-to/reject-client-connections.md b/docs/docs/how-to/reject-client-connections.md new file mode 100644 index 00000000000..45638b2e739 --- /dev/null +++ b/docs/docs/how-to/reject-client-connections.md @@ -0,0 +1,56 @@ +# Rejecting Client Connections + +SpacetimeDB provides a way to disconnect a client during a client connection attempt. + +:::server-rust +In Rust, if we returned and error (or a panic) during the `client_connected` reducer, the client will be disconnected. + +Here is a simple example where the server module throws an error for all incoming client connections. +```rust +#[reducer(client_connected)] +pub fn client_connected(_ctx: &ReducerContext) -> Result<(), String> { + let client_is_rejected = true; + if client_is_rejected { + Err("The client connection was rejected. With our current code logic, all clients will be rejected.".to_string()) + } else { + Ok(()) + } +} +``` + +Client behavior can vary by client type. For example: +* **C# clients**: Client disconnection behavior is currently undefined and will generate an error reading: + `Disconnected abnormally: System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.` + +* **Rust clients**: Client disconnection behavior is currently undefined and will generate an error reading: + `Unable to send subscribe message: WS sender loop has dropped its recv channel: TrySendError { kind: Disconnected }` + +* **TypeScript clients**: Client will receive an `Error connecting to SpacetimeDB:` and a `CloseEvent` with a code of 1006. + +Regardless of the client type, from the rust server's perspective, the client will be disconnected and the server module's logs will contain an entry reading: +`ERROR: : The client connection was rejected. With our current code logic, all clients will be rejected.` +::: +:::server-csharp +In C#, if we throw an exception during the `ClientConnected` reducer, the client will be disconnected. + +Here is a simple example where the server module throws an error for all incoming client connections. +```csharp +[Reducer(ReducerKind.ClientConnected)] +// Called when a client connects to a SpacetimeDB database server +public static void ClientConnected(ReducerContext ctx) +{ + throw new Exception("The client connection was rejected. With our current code logic, all clients will be rejected."); +} +``` + +Client behavior can vary by client type. For example: +* **C# clients**: Client disconnection behavior is currently undefined and will generate an error reading: +`Disconnected abnormally: System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.` + +* **Rust clients**: Client will receive an `on_disconnected` event with no error message. + +* **TypeScript clients**: Client will receive an `Error connecting to SpacetimeDB:` and a `CloseEvent` with a code of 1006. + +Regardless of the client type, from the C# server's perspective, the client will be disconnected and the server module's logs will contain an entry reading: +`ERROR: : System.Exception: The client connection was rejected. With our current code logic, all clients will be rejected.` +::: From 1d6e61f31fc7d8a8ef6bad7dbedc451d0e2ad004 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Fri, 25 Jul 2025 10:24:35 -0700 Subject: [PATCH 2/4] Adds Reject Client Connects doc to the NavBar --- docs/nav.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/nav.ts b/docs/nav.ts index 7dff8490531..b5e854ca807 100644 --- a/docs/nav.ts +++ b/docs/nav.ts @@ -96,6 +96,7 @@ const nav: Nav = { section('How To'), page('Incremental Migrations', 'how-to/incremental-migrations', 'how-to/incremental-migrations.md'), + page('Reject Client Connections', 'how-to/reject-client-connections', 'how-to/reject-client-connections.md'), section('HTTP API'), page('Authorization', 'http/authorization', 'http/authorization.md'), From 8845abcdfe0f731cc2033b373b492dfc2fcd4341 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Fri, 25 Jul 2025 10:29:13 -0700 Subject: [PATCH 3/4] Added Reject Client Connections to NavBar JavaScript doc --- docs/docs/nav.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/nav.js b/docs/docs/nav.js index 3082ea7a702..b19f226d9bb 100644 --- a/docs/docs/nav.js +++ b/docs/docs/nav.js @@ -44,6 +44,7 @@ const nav = { page('Row Level Security', 'rls', 'rls/index.md'), section('How To'), page('Incremental Migrations', 'how-to/incremental-migrations', 'how-to/incremental-migrations.md'), + page('Reject Client Connections', 'how-to/reject-client-connections', 'how-to/reject-client-connections.md'), section('HTTP API'), page('Authorization', 'http/authorization', 'http/authorization.md'), page('`/identity`', 'http/identity', 'http/identity.md'), From 603d6f601750bea6bf0c90d57d907c56de00da1a Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Fri, 25 Jul 2025 10:31:40 -0700 Subject: [PATCH 4/4] [rekhoff/docs-reject-client-connections]: fix nav.js --- docs/docs/nav.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/nav.js b/docs/docs/nav.js index b19f226d9bb..5b6e3d1a968 100644 --- a/docs/docs/nav.js +++ b/docs/docs/nav.js @@ -44,7 +44,7 @@ const nav = { page('Row Level Security', 'rls', 'rls/index.md'), section('How To'), page('Incremental Migrations', 'how-to/incremental-migrations', 'how-to/incremental-migrations.md'), - page('Reject Client Connections', 'how-to/reject-client-connections', 'how-to/reject-client-connections.md'), + page('Reject Client Connections', 'how-to/reject-client-connections', 'how-to/reject-client-connections.md'), section('HTTP API'), page('Authorization', 'http/authorization', 'http/authorization.md'), page('`/identity`', 'http/identity', 'http/identity.md'),