|
| 1 | +using BotSharp.Abstraction.Realtime; |
1 | 2 | using BotSharp.Abstraction.Realtime.Options; |
2 | 3 | using BotSharp.Abstraction.Realtime.Sessions; |
| 4 | +using BotSharp.Core.Infrastructures; |
3 | 5 | using BotSharp.Core.Session; |
4 | 6 | using Microsoft.AspNetCore.Http; |
5 | 7 | using System.Net.WebSockets; |
@@ -34,6 +36,23 @@ public async Task Invoke(HttpContext httpContext) |
34 | 36 | var agentId = segments[segments.Length - 2]; |
35 | 37 | var conversationId = segments[segments.Length - 1]; |
36 | 38 |
|
| 39 | + /* |
| 40 | + * Identity, before anything else touches the connection. |
| 41 | + * |
| 42 | + * The handshake carries no Authorization header - a browser cannot set one on |
| 43 | + * a WebSocket - so the signed-in user arrives as a query parameter. It stays |
| 44 | + * a query parameter rather than a path segment because agentId and |
| 45 | + * conversationId are read from the END of the path above, so an extra segment |
| 46 | + * would silently shift both. |
| 47 | + * |
| 48 | + * Emitted through the SYNCHRONOUS Emit overload: ambient identity is |
| 49 | + * AsyncLocal-backed and a write inside an async method does not escape it, so |
| 50 | + * an awaited hook would establish nothing for the work awaited below. |
| 51 | + */ |
| 52 | + var userId = httpContext.Request.Query["user-id"].FirstOrDefault(); |
| 53 | + HookEmitter.Emit<IRealtimeHook>(services, |
| 54 | + hook => hook.OnAuthenticate(agentId, conversationId, userId), agentId); |
| 55 | + |
37 | 56 | using var webSocket = await httpContext.WebSockets.AcceptWebSocketAsync(); |
38 | 57 | await HandleWebSocket(services, agentId, conversationId, webSocket); |
39 | 58 | } |
|
0 commit comments