Add: Dauerhaftes Bildschirm-Übertragung-Overlay während RDP-Session (v2.6.0)
- RdpActiveIndicatorWindow: TeamViewer-Style Overlay unten rechts, solange RDP-Capture läuft. Zeigt Dauer der Sitzung + pulsierenden roten Punkt - User kann per "Trennen"-Button selbst die Sitzung beenden (TCP-Signal an Service, cancelt Capture-Loop sofort — auch nach Screen-Wechsel) - Overlay läuft als separater User-Prozess via SessionSpawner, wird vom Service direkt gekillt wenn Sitzung endet (rdp_stop oder Disconnect) - Version: 2.5.0 → 2.6.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,9 @@ public class RtcService
|
||||
private readonly string _serverUrl;
|
||||
private readonly string _agentKey;
|
||||
private readonly string _hostname;
|
||||
private int _indicatorPid = -1;
|
||||
private TcpListener? _indicatorListener;
|
||||
private CancellationTokenSource? _userDisconnectCts;
|
||||
|
||||
public RtcService(string serverUrl, string agentKey, string hostname)
|
||||
{
|
||||
@@ -76,21 +79,39 @@ public class RtcService
|
||||
var newScreen = obj["screen"]?.ToObject<int>() ?? 0;
|
||||
captureCts.Cancel();
|
||||
captureCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
_ = CapturePipeLoopAsync(ws, newScreen, captureCts.Token);
|
||||
var switchToken = _userDisconnectCts != null
|
||||
? CancellationTokenSource.CreateLinkedTokenSource(captureCts.Token, _userDisconnectCts.Token).Token
|
||||
: captureCts.Token;
|
||||
_ = CapturePipeLoopAsync(ws, newScreen, switchToken);
|
||||
AgentWorker.Log($"RDP: Screen gewechselt zu {newScreen}");
|
||||
}
|
||||
else if (type == "rdp_stop" && captureCts != null)
|
||||
{
|
||||
captureCts.Cancel();
|
||||
captureCts = null;
|
||||
StopIndicator();
|
||||
AgentWorker.Log("RDP: Screen-Capture gestoppt");
|
||||
}
|
||||
}
|
||||
|
||||
captureCts?.Cancel();
|
||||
StopIndicator();
|
||||
AgentWorker.Log("RDP: Getrennt");
|
||||
}
|
||||
|
||||
private void StopIndicator()
|
||||
{
|
||||
_userDisconnectCts?.Cancel();
|
||||
_userDisconnectCts = null;
|
||||
try { _indicatorListener?.Stop(); } catch { }
|
||||
_indicatorListener = null;
|
||||
if (_indicatorPid > 0)
|
||||
{
|
||||
try { Process.GetProcessById(_indicatorPid).Kill(); } catch { }
|
||||
_indicatorPid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ConsentAndCaptureAsync(ClientWebSocket ws, int screenIdx, CancellationToken ct)
|
||||
{
|
||||
var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName;
|
||||
@@ -136,7 +157,45 @@ public class RtcService
|
||||
}
|
||||
|
||||
AgentWorker.Log("RDP: User hat Zugriff erlaubt, starte Capture");
|
||||
await CapturePipeLoopAsync(ws, screenIdx, ct);
|
||||
SpawnIndicator(exePath);
|
||||
|
||||
var combinedToken = _userDisconnectCts != null
|
||||
? CancellationTokenSource.CreateLinkedTokenSource(ct, _userDisconnectCts.Token).Token
|
||||
: ct;
|
||||
await CapturePipeLoopAsync(ws, screenIdx, combinedToken);
|
||||
}
|
||||
|
||||
// Zeigt dauerhaftes "Bildschirm wird übertragen"-Overlay (TeamViewer-Style) solange Capture läuft.
|
||||
// User kann per Klick selbst trennen — Signal landet hier als CancellationTokenSource.Cancel().
|
||||
private void SpawnIndicator(string exePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
_indicatorListener = new TcpListener(IPAddress.Loopback, 0);
|
||||
_indicatorListener.Start();
|
||||
var port = ((IPEndPoint)_indicatorListener.LocalEndpoint).Port;
|
||||
|
||||
_userDisconnectCts = new CancellationTokenSource();
|
||||
var listener = _indicatorListener;
|
||||
var disconnectCts = _userDisconnectCts;
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var tcp = await listener.AcceptTcpClientAsync();
|
||||
tcp.GetStream().ReadByte();
|
||||
disconnectCts.Cancel();
|
||||
AgentWorker.Log("RDP: User hat über Overlay getrennt");
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
_indicatorPid = SessionSpawner.SpawnInUserSession(exePath, $"--rdp-indicator {port}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AgentWorker.Log($"RDP: Indicator-Start fehlgeschlagen: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool SpawnConsentHelper(string exePath, string portStr)
|
||||
|
||||
Reference in New Issue
Block a user