mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 08:36:11 +02:00
deploy: 4a598aa8a8
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user