Summary Update.
This commit is contained in:
@@ -6,14 +6,39 @@ using RelayShared.Services;
|
||||
|
||||
namespace RelayClient.Services;
|
||||
|
||||
/// <summary>
|
||||
/// The bridge between the C# WebSocket pipe and the JavaScript WebRTC engine
|
||||
/// running inside the HybridWebView (which is shown when a Voice channel is open).
|
||||
///
|
||||
/// Outbound (JS → C# → server): the WebView JS calls into C# via SendRtcSignal(json).
|
||||
/// We deserialise to RtcSignalMessage, encrypt with the server's public key, wrap in
|
||||
/// SocketRtcSignalMessage, and send through the WebSocket.
|
||||
///
|
||||
/// Inbound (server → C# → JS): the WebSocket fires EncryptedRtcSignalReceived. MainPage
|
||||
/// hands it to HandleIncomingRtcSignalAsync, which decrypts with the user's private key
|
||||
/// and calls back into JS via hybridWebView.InvokeJavaScriptAsync("testIndex", …).
|
||||
///
|
||||
/// JoinRtcChannel / LeaveRtcChannel just send WsAction control messages; presence tracking
|
||||
/// happens server-side in RtcChannelPresenceService.
|
||||
/// </summary>
|
||||
public sealed class RtcBridgeService
|
||||
{
|
||||
/// <summary>The currently-signed-in username. Stamped onto outgoing RTC signals.</summary>
|
||||
private readonly string _username;
|
||||
|
||||
/// <summary>The shared WebSocket to RelayServer. Outbound RTC signals ride on this.</summary>
|
||||
private readonly RelaySocketClient _socket;
|
||||
|
||||
/// <summary>The MAUI HybridWebView that hosts the JS WebRTC engine. We push JS calls into it.</summary>
|
||||
private readonly HybridWebView _hybridWebView;
|
||||
|
||||
/// <summary>Lazy view into MainPage._currentChannelId so we always have the current voice channel.</summary>
|
||||
private readonly Func<string?> _getCurrentChannelId;
|
||||
|
||||
/// <summary>Diagnostic logger that surfaces messages back to the WebView UI. Used for status/error reporting.</summary>
|
||||
private readonly Action<string> _sendRawToWebView;
|
||||
|
||||
/// <summary>Captures collaborators. MainPage constructs this once and never replaces it.</summary>
|
||||
public RtcBridgeService(string username, RelaySocketClient socket, HybridWebView hybridWebView,
|
||||
Func<string?> getCurrentChannelId, Action<string> sendRawToWebView)
|
||||
{
|
||||
@@ -24,6 +49,7 @@ public sealed class RtcBridgeService
|
||||
_sendRawToWebView = sendRawToWebView;
|
||||
}
|
||||
|
||||
/// <summary>Sends RtcJoin for the currently-selected channel. Server-side, this triggers the Speak permission check and presence registration.</summary>
|
||||
public Task JoinRtcChannel()
|
||||
{
|
||||
var channelId = _getCurrentChannelId();
|
||||
@@ -35,6 +61,7 @@ public sealed class RtcBridgeService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Sends RtcLeave for the currently-selected channel. Clears server-side voice presence so peers stop seeing us.</summary>
|
||||
public void LeaveRtcChannel()
|
||||
{
|
||||
var channelId = _getCurrentChannelId();
|
||||
@@ -45,6 +72,13 @@ public sealed class RtcBridgeService
|
||||
_socket.SendRtcLeaveChannel(channelId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from JavaScript (via the HybridWebView bridge) when the WebRTC engine wants to
|
||||
/// send an SDP offer/answer or ICE candidate to other peers. Parses the JSON, fills in
|
||||
/// missing ChannelId/From, encrypts with the server's public key, ships as
|
||||
/// SocketRtcSignalMessage. The server then forwards it (re-encrypted per-recipient) to
|
||||
/// every other session in the same voice channel.
|
||||
/// </summary>
|
||||
public void SendRtcSignal(string json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_socket.ServerPublicKey))
|
||||
@@ -105,6 +139,7 @@ public sealed class RtcBridgeService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>JS bridge: returns the current voice-channel roster as JSON. Hits ServerAPI's REST endpoint, not the WebSocket.</summary>
|
||||
public async Task<string> GetRtcParticipants()
|
||||
{
|
||||
var channelId = _getCurrentChannelId();
|
||||
@@ -116,6 +151,11 @@ public sealed class RtcBridgeService
|
||||
return JsonSerializer.Serialize(participants ?? []);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MainPage hands incoming SocketRtcSignalMessage frames here. Filters out our own
|
||||
/// frames, validates the channel scope, decrypts with the user's private key, parses to
|
||||
/// RtcSignalMessage, then pushes into the JS RTC engine via SendRtcSignalToJsAsync.
|
||||
/// </summary>
|
||||
public async Task HandleIncomingRtcSignalAsync(SocketRtcSignalMessage payload)
|
||||
{
|
||||
// _sendRawToWebView("HandleIncomingRtcSignal called");
|
||||
@@ -187,6 +227,10 @@ public sealed class RtcBridgeService
|
||||
await SendRtcSignalToJsAsync(rtcSignal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes the current username and channelId into JS globals (window.setUsername, window.setChannelId).
|
||||
/// Called whenever the user switches voice channels OR the JS engine reports rtc_page_ready.
|
||||
/// </summary>
|
||||
public Task PushRtcContextToJsAsync()
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(async () =>
|
||||
@@ -201,6 +245,11 @@ public sealed class RtcBridgeService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Final hop: hands a decrypted RtcSignalMessage off to the JS engine via
|
||||
/// hybridWebView.InvokeJavaScriptAsync("testIndex", …). SDP strings have their newlines
|
||||
/// escaped as "(rn)" because the JSON marshalling otherwise breaks them.
|
||||
/// </summary>
|
||||
private Task SendRtcSignalToJsAsync(RtcSignalMessage data)
|
||||
{
|
||||
if (data.Type == "rtc_offer" || data.Type == "rtc_answer")
|
||||
|
||||
Reference in New Issue
Block a user