# Connection | EchoHub Documentation

# Connection

## SignalR Client Connection

After authentication, the TUI client establishes a SignalR WebSocket, registers event handlers, joins the default channel, and loads history.

    sequenceDiagram
        participant CM as ConnectionManager
        participant EHC as EchoHubConnection
        participant Hub as ChatHub
        participant CS as ChatService
        participant PT as PresenceTracker
        participant DB as SQLite

        CM->>CM: Fetch encryption key (GET /api/server/encryption-key)
        CM->>EHC: new EchoHubConnection(apiClient, encryption)
        EHC->>EHC: Build HubConnection (URL + JWT token provider + auto-reconnect)
        EHC->>EHC: RegisterHandlers() — wire ReceiveMessage, UserJoined, etc.
        EHC->>Hub: ConnectAsync() → WebSocket handshake
        Hub->>CS: UserConnectedAsync(connectionId, userId, username)
        CS->>PT: UserConnected(connectionId, userId, username)
        CS->>DB: Update user: Status=Online, LastSeenAt=now
        CM->>CM: Fetch channel list (GET /api/channels)
        CM->>EHC: JoinChannelAsync("general")
        EHC->>Hub: InvokeAsync("JoinChannel", "general")
        Hub->>CS: JoinChannelAsync(connectionId, userId, username, "general")
        CS->>DB: EnsureChannelMembership
        CS->>PT: JoinChannel(username, "general")
        CS->>CS: BroadcastToAllAsync → UserJoined
        CS->>DB: Fetch message history
        Hub-->>EHC: List<MessageDto> (encrypted)
        EHC-->>CM: Decrypted history

## IRC Client Connection

IRC clients connect via TCP, authenticate with PASS/NICK/USER or SASL PLAIN, and auto-join channels. New usernames are auto-registered.

    sequenceDiagram
        participant IRC as IRC Client
        participant GW as IrcGatewayService
        participant CH as IrcCommandHandler
        participant US as UserService
        participant CS as ChatService
        participant PT as PresenceTracker

        IRC->>GW: TCP connect (:6667 or :6697 TLS)
        GW->>GW: Accept + create IrcClientConnection
        GW->>CH: new IrcCommandHandler(connection, services)
        GW->>CH: RunAsync() — start read loop

        alt SASL PLAIN
            IRC->>CH: CAP REQ :sasl
            CH-->>IRC: CAP ACK :sasl
            IRC->>CH: AUTHENTICATE PLAIN
            CH-->>IRC: AUTHENTICATE +
            IRC->>CH: AUTHENTICATE <base64(\0user\0pass)>
            CH->>US: AuthenticateUserAsync(user, pass)
            alt Auth fails → auto-register
                CH->>US: RegisterUserAsync(user, pass)
            end
            CH-->>IRC: 903 :SASL authentication successful
        else PASS/NICK/USER
            IRC->>CH: PASS <password>
            IRC->>CH: NICK <nickname>
            IRC->>CH: USER <username> 0 * :<realname>
            CH->>US: AuthenticateUserAsync(nick, pass)
            alt Auth fails → auto-register
                CH->>US: RegisterUserAsync(nick, pass)
            end
        end

        CH->>CS: UserConnectedAsync(irc-{guid}, userId, username)
        CS->>PT: UserConnected(irc-{guid}, userId, username)
        CH-->>IRC: 001-004 RPL_WELCOME burst + MOTD

        Note over IRC,CH: Client is now ready for JOIN/PART/PRIVMSG

## User Disconnect & Presence

When a client disconnects, the presence tracker determines if the user has any remaining connections. If not, status is set to Invisible and all channels are notified.

    sequenceDiagram
        participant Client as Client
        participant Entry as ChatHub / IrcGatewayService
        participant CS as ChatService
        participant PT as PresenceTracker
        participant DB as SQLite
        participant SRB as SignalRBroadcaster

        Client->>Entry: Disconnect / TCP close
        Entry->>CS: UserDisconnectedAsync(connectionId)
        CS->>PT: Get username + channels (before removal)
        CS->>PT: UserDisconnected(connectionId)
        PT->>PT: Remove connection from tracking

        alt No remaining connections for user
            CS->>DB: Update user: Status=Invisible, LastSeenAt=now
            loop For each channel user was in
                CS->>CS: BroadcastToAllAsync(SendUserStatusChangedAsync)
                CS->>SRB: Notify channel members
            end
        end