mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 16:46:08 +02:00
349 lines
12 KiB
HTML
349 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Connection | EchoHub Documentation </title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="title" content="Connection | EchoHub Documentation ">
|
|
|
|
|
|
<link rel="icon" href="../images/hue_icon.svg">
|
|
<link rel="stylesheet" href="../public/docfx.min.css">
|
|
<link rel="stylesheet" href="../public/main.css">
|
|
<meta name="docfx:navrel" content="../toc.html">
|
|
<meta name="docfx:tocrel" content="toc.html">
|
|
|
|
<meta name="docfx:rel" content="../">
|
|
|
|
|
|
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
|
|
<meta name="loc:inThisArticle" content="In this article">
|
|
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
|
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
|
<meta name="loc:tocFilter" content="Filter by title">
|
|
<meta name="loc:nextArticle" content="Next">
|
|
<meta name="loc:prevArticle" content="Previous">
|
|
<meta name="loc:themeLight" content="Light">
|
|
<meta name="loc:themeDark" content="Dark">
|
|
<meta name="loc:themeAuto" content="Auto">
|
|
<meta name="loc:changeTheme" content="Change theme">
|
|
<meta name="loc:copy" content="Copy">
|
|
<meta name="loc:downloadPdf" content="Download PDF">
|
|
|
|
<script type="module" src="./../public/docfx.min.js"></script>
|
|
|
|
<script>
|
|
const theme = localStorage.getItem('theme') || 'auto'
|
|
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
|
<header class="bg-body border-bottom">
|
|
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
|
<div class="container-xxl flex-nowrap">
|
|
<a class="navbar-brand" href="../index.html">
|
|
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
|
|
EchoHub
|
|
</a>
|
|
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
|
<i class="bi bi-three-dots"></i>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navpanel">
|
|
<div id="navbar">
|
|
<form class="search" role="search" id="search">
|
|
<i class="bi bi-search"></i>
|
|
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="container-xxl">
|
|
<div class="toc-offcanvas">
|
|
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<nav class="toc" id="toc"></nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="actionbar">
|
|
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
|
<i class="bi bi-list"></i>
|
|
</button>
|
|
|
|
<nav id="breadcrumb"></nav>
|
|
</div>
|
|
|
|
<article data-uid="">
|
|
<h1 id="connection">Connection</h1>
|
|
|
|
<h2 id="signalr-client-connection">SignalR Client Connection</h2>
|
|
<p>After authentication, the TUI client establishes a SignalR WebSocket, registers
|
|
event handlers, joins the default channel, and loads history.</p>
|
|
<pre><code class="lang-mermaid">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
|
|
</code></pre>
|
|
<p><strong>Code references:</strong></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Step</th>
|
|
<th>File</th>
|
|
<th>Location</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Connection orchestration</td>
|
|
<td><code>src/EchoHub.Client/Services/ConnectionManager.cs</code></td>
|
|
<td>Lines 58-140 (<code>ConnectAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>EchoHubConnection setup</td>
|
|
<td><code>src/EchoHub.Client/Services/EchoHubConnection.cs</code></td>
|
|
<td>Lines 29-62 (constructor)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Handler registration</td>
|
|
<td><code>src/EchoHub.Client/Services/EchoHubConnection.cs</code></td>
|
|
<td>Lines 64-122 (<code>RegisterHandlers</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Hub OnConnected</td>
|
|
<td><code>src/EchoHub.Server/Hubs/ChatHub.cs</code></td>
|
|
<td>Lines 31-43</td>
|
|
</tr>
|
|
<tr>
|
|
<td>ChatService connected</td>
|
|
<td><code>src/EchoHub.Server/Services/ChatService.cs</code></td>
|
|
<td>Lines 41-57</td>
|
|
</tr>
|
|
<tr>
|
|
<td>PresenceTracker connect</td>
|
|
<td><code>src/EchoHub.Server/Services/PresenceTracker.cs</code></td>
|
|
<td>Lines 13-29</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Join channel (hub)</td>
|
|
<td><code>src/EchoHub.Server/Hubs/ChatHub.cs</code></td>
|
|
<td>Lines 59-81</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Join channel (service)</td>
|
|
<td><code>src/EchoHub.Server/Services/ChatService.cs</code></td>
|
|
<td>Lines 96-135</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr>
|
|
<h2 id="irc-client-connection">IRC Client Connection</h2>
|
|
<p>IRC clients connect via TCP, authenticate with PASS/NICK/USER or SASL PLAIN,
|
|
and auto-join channels. New usernames are auto-registered.</p>
|
|
<pre><code class="lang-mermaid">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
|
|
</code></pre>
|
|
<p><strong>Code references:</strong></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Step</th>
|
|
<th>File</th>
|
|
<th>Location</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>TCP listener</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcGatewayService.cs</code></td>
|
|
<td>Lines 45-90 (<code>ExecuteAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Client handler</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcGatewayService.cs</code></td>
|
|
<td>Lines 92-154 (<code>HandleClientAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Command read loop</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcCommandHandler.cs</code></td>
|
|
<td>Lines 40-98 (<code>RunAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>SASL auth</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcCommandHandler.cs</code></td>
|
|
<td>Lines 136-207 (<code>HandleAuthenticateAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>PASS/NICK/USER</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcCommandHandler.cs</code></td>
|
|
<td>Lines 209-267</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Registration completion</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcCommandHandler.cs</code></td>
|
|
<td>Lines 268-315 (<code>TryCompleteRegistrationAsync</code>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Cleanup on disconnect</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcGatewayService.cs</code></td>
|
|
<td>Lines 136-153</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr>
|
|
<h2 id="user-disconnect--presence">User Disconnect & Presence</h2>
|
|
<p>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.</p>
|
|
<pre><code class="lang-mermaid">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
|
|
</code></pre>
|
|
<p><strong>Code references:</strong></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Step</th>
|
|
<th>File</th>
|
|
<th>Location</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>SignalR disconnect</td>
|
|
<td><code>src/EchoHub.Server/Hubs/ChatHub.cs</code></td>
|
|
<td>Lines 45-57</td>
|
|
</tr>
|
|
<tr>
|
|
<td>IRC cleanup</td>
|
|
<td><code>src/EchoHub.Server.Irc/IrcGatewayService.cs</code></td>
|
|
<td>Lines 136-153</td>
|
|
</tr>
|
|
<tr>
|
|
<td>ChatService disconnect</td>
|
|
<td><code>src/EchoHub.Server/Services/ChatService.cs</code></td>
|
|
<td>Lines 59-94</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Presence disconnect</td>
|
|
<td><code>src/EchoHub.Server/Services/PresenceTracker.cs</code></td>
|
|
<td>Lines 31-53</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
</article>
|
|
|
|
<div class="contribution d-print-none">
|
|
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
|
|
</div>
|
|
|
|
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
|
|
|
</div>
|
|
|
|
<div class="affix">
|
|
<nav id="affix"></nav>
|
|
</div>
|
|
</main>
|
|
|
|
<div class="container-xxl search-results" id="search-results"></div>
|
|
|
|
<footer class="border-top text-secondary">
|
|
<div class="container-xxl">
|
|
<div class="flex-fill">
|
|
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a><span class='footer-sep'>·</span><span class='footer-credit'>Built with <a href='https://dotnet.github.io/docfx'>DocFX</a></span></div></div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|