Generated by AurionDocs
Job ID: 934f8c39-8082-4942-8d17-72ed8f5f8d50
Source commit: 40aea9a
5.4 KiB
ChatHub
File:
src/EchoHub.Server/Hubs/ChatHub.cs
Kind: class
Figure: How ChatHub works.
%%{init: {'theme':'base','themeVariables':{'background':'#faf7ef','primaryColor':'#f0e2c2','primaryTextColor':'#1f2840','primaryBorderColor':'#8a7548','secondaryColor':'#d9efec','secondaryBorderColor':'#1d8a80','secondaryTextColor':'#1f2840','tertiaryColor':'#f2ebd8','tertiaryBorderColor':'#8a7548','tertiaryTextColor':'#1f2840','lineColor':'#1d8a80','titleColor':'#1f2840','fontSize':'14px','edgeLabelBackground':'#faf7ef','clusterBkg':'#f2ebd8','clusterBorder':'#8a7548','actorBkg':'#f0e2c2','actorBorder':'#8a7548','actorTextColor':'#1f2840','actorLineColor':'#8a7548','signalColor':'#1d8a80','signalTextColor':'#1f2840','activationBkgColor':'#d9efec','activationBorderColor':'#1d8a80','noteBkgColor':'#f2ebd8','noteBorderColor':'#8a7548','noteTextColor':'#1f2840','labelBoxBkgColor':'#f0e2c2','labelBoxBorderColor':'#8a7548','labelTextColor':'#1f2840','transitionColor':'#1d8a80','transitionLabelColor':'#1f2840','stateLabelColor':'#1f2840','altBackground':'#f2ebd8'}}}%%
flowchart TB
start["Incoming Hub action to ChatHub"]
start --> onConn["OnConnectedAsync"]
onConn --> callUserConnected["Call IChatService.UserConnectedAsync(Context.ConnectionId, CurrentUserId, CurrentUsername)"]
callUserConnected --> baseOnConn["Call base.OnConnectedAsync()"]
callUserConnected -->|"exception"| onConnLog["Log error via ILogger and rethrow"]
baseOnConn --> onConnEnd["OnConnectedAsync returns"]
start --> onDisc["OnDisconnectedAsync"]
onDisc --> callUserDisconnected["Call IChatService.UserDisconnectedAsync(Context.ConnectionId)"]
callUserDisconnected --> baseOnDisc["Call base.OnDisconnectedAsync(exception)"]
callUserDisconnected -->|"exception"| onDiscLog["Log error via ILogger and rethrow"]
baseOnDisc --> onDiscEnd["OnDisconnectedAsync returns"]
start --> join["JoinChannel(channelName, password?)"]
join --> callJoinService["Call IChatService.JoinChannelAsync(Context.ConnectionId, CurrentUserId, CurrentUsername, channelName, password)"]
callJoinService --> joinDecision{"error is not null?"}
joinDecision -->|"yes"| joinReturnError["Return JoinChannelResult(false, [], error, passwordRequired)"]
joinDecision -->|"no"| addGroup["Call Groups.AddToGroupAsync(Context.ConnectionId, channelName.ToLowerInvariant().Trim())"]
addGroup --> getEnvelope["Call IChannelService.GetChannelKeyEnvelopeAsync(channelName)"]
getEnvelope --> joinReturnSuccess["Return JoinChannelResult(true, history, EncryptionSalt, WrappedRoomKey)"]
callJoinService -->|"exception"| joinExceptionLog["Log error via ILogger; Return JoinChannelResult(false, [], Failed to join channel: ex.Message)"]
start --> leave["LeaveChannel(channelName)"]
leave --> normalize["Normalize channelName to lowerInvariant and trim"]
normalize --> callLeaveService["Call IChatService.LeaveChannelAsync(Context.ConnectionId, CurrentUsername, channelName)"]
callLeaveService --> removeFromGroup["Call Groups.RemoveFromGroupAsync(Context.ConnectionId, channelName)"]
callLeaveService -->|"exception"| leaveExceptionLog["Log error via ILogger"]
[Authorize]
public class ChatHub : Hub<IEchoHubClient>
A SignalR hub that exposes real-time chat operations (connect/disconnect, join/leave channel, send messages) and bridges authenticated SignalR connections with the domain services that manage presence, channels and message delivery. Reach for ChatHub when you need a server-side, authenticated entry point that coordinates IChatService and IChannelService, manages SignalR groups, and forwards notifications to clients via the IEchoHubClient callbacks.
Remarks
ChatHub is a thin application-layer adapter: it enforces authentication (the class is decorated with Authorize), resolves the current user from the SignalR Context claims via CurrentUserId and CurrentUsername, and delegates core logic to IChatService and IChannelService. It is responsible for SignalR group membership using Groups.AddToGroupAsync / Groups.RemoveFromGroupAsync, for logging errors via ILogger<ChatHub>, and for returning protocol-shaped results such as JoinChannelResult and client-facing error messages through the IEchoHubClient.Error callback. The hub intentionally does not perform domain operations itself — it translates connection-level events and client requests into calls to the underlying services and shapes the responses for connected clients.
Notes
CurrentUserIdandCurrentUsernamethrow aHubExceptionif the expected claims are absent; theAuthorizeattribute reduces this risk, but any token must containClaimTypes.NameIdentifierand a"username"claim for the hub to function.- Channel names are normalized with
channelName.ToLowerInvariant().Trim()before being used with SignalR groups; callers and services must use the same normalization to avoid mismatches in group membership. - When
JoinChannelsucceeds for an encrypted channel the hub returns the channel key envelope obtained fromIChannelService.GetChannelKeyEnvelopeAsync(the server comment notes members unwrap the room key client-side); do not expect the server to decrypt room content for clients.