Initial project snapshot

This commit is contained in:
2026-04-28 22:29:50 +03:00
commit 8ba0561f4f
365 changed files with 91832 additions and 0 deletions
@@ -0,0 +1,12 @@
namespace Rap.Rdp.Core;
public interface IRapDataPlaneBridge : IAsyncDisposable
{
ValueTask StartAsync(RdpSessionDescriptor session, CancellationToken cancellationToken);
ValueTask StopAsync(CancellationToken cancellationToken);
event Func<RdpInputEvent, CancellationToken, ValueTask>? InputReceived;
event Func<string, CancellationToken, ValueTask>? ClipboardTextReceived;
}
@@ -0,0 +1,43 @@
namespace Rap.Rdp.Core;
public interface IRdpGraphicsSink
{
ValueTask PublishSurfaceAsync(RdpSurfaceUpdate update, CancellationToken cancellationToken);
ValueTask PublishCursorAsync(RdpCursorUpdate update, CancellationToken cancellationToken);
}
public abstract record RdpSurfaceUpdate(
long Sequence,
string UpdateKind,
DateTimeOffset CapturedAt);
public sealed record RdpRawBitmapUpdate(
long Sequence,
DateTimeOffset CapturedAt,
int X,
int Y,
int Width,
int Height,
int DesktopWidth,
int DesktopHeight,
string PixelFormat,
ReadOnlyMemory<byte> Pixels) : RdpSurfaceUpdate(Sequence, "raw_bitmap", CapturedAt);
public sealed record RdpEncodedGraphicsUpdate(
long Sequence,
DateTimeOffset CapturedAt,
int SurfaceId,
string Codec,
int X,
int Y,
int Width,
int Height,
ReadOnlyMemory<byte> Payload) : RdpSurfaceUpdate(Sequence, "encoded_graphics", CapturedAt);
public sealed record RdpCursorUpdate(
long Sequence,
int X,
int Y,
bool Visible,
DateTimeOffset CapturedAt);
@@ -0,0 +1,39 @@
namespace Rap.Rdp.Core;
public interface IRdpProtocolEngine : IAsyncDisposable
{
ValueTask ConnectAsync(RdpSessionDescriptor session, CancellationToken cancellationToken);
ValueTask DisconnectAsync(bool terminateRemoteSession, CancellationToken cancellationToken);
ValueTask SendInputAsync(RdpInputEvent inputEvent, CancellationToken cancellationToken);
ValueTask SendClipboardTextAsync(string text, CancellationToken cancellationToken);
}
public abstract record RdpInputEvent(string CorrelationId);
public sealed record RdpKeyboardEvent(
string CorrelationId,
ushort ScanCode,
bool KeyDown,
bool Extended) : RdpInputEvent(CorrelationId);
public sealed record RdpPointerMoveEvent(
string CorrelationId,
double NormalizedX,
double NormalizedY) : RdpInputEvent(CorrelationId);
public sealed record RdpPointerButtonEvent(
string CorrelationId,
string Button,
bool Pressed,
double NormalizedX,
double NormalizedY) : RdpInputEvent(CorrelationId);
public sealed record RdpPointerWheelEvent(
string CorrelationId,
int Delta,
bool Horizontal,
double NormalizedX,
double NormalizedY) : RdpInputEvent(CorrelationId);
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
@@ -0,0 +1,54 @@
namespace Rap.Rdp.Core;
public sealed class RdpServiceSession(
RdpSessionDescriptor descriptor,
IRdpProtocolEngine protocolEngine,
IRapDataPlaneBridge dataPlaneBridge)
: IAsyncDisposable
{
private readonly CancellationTokenSource _lifetime = new();
private int _started;
public RdpSessionDescriptor Descriptor { get; } = descriptor;
public async ValueTask StartAsync(CancellationToken cancellationToken)
{
if (Interlocked.Exchange(ref _started, 1) == 1)
{
return;
}
using var linked = CancellationTokenSource.CreateLinkedTokenSource(_lifetime.Token, cancellationToken);
dataPlaneBridge.InputReceived += OnInputReceivedAsync;
dataPlaneBridge.ClipboardTextReceived += OnClipboardTextReceivedAsync;
await protocolEngine.ConnectAsync(Descriptor, linked.Token).ConfigureAwait(false);
await dataPlaneBridge.StartAsync(Descriptor, linked.Token).ConfigureAwait(false);
}
public async ValueTask StopAsync(bool terminateRemoteSession, CancellationToken cancellationToken)
{
_lifetime.Cancel();
await dataPlaneBridge.StopAsync(cancellationToken).ConfigureAwait(false);
await protocolEngine.DisconnectAsync(terminateRemoteSession, cancellationToken).ConfigureAwait(false);
}
private ValueTask OnInputReceivedAsync(RdpInputEvent inputEvent, CancellationToken cancellationToken)
{
return protocolEngine.SendInputAsync(inputEvent, cancellationToken);
}
private ValueTask OnClipboardTextReceivedAsync(string text, CancellationToken cancellationToken)
{
return protocolEngine.SendClipboardTextAsync(text, cancellationToken);
}
public async ValueTask DisposeAsync()
{
_lifetime.Cancel();
dataPlaneBridge.InputReceived -= OnInputReceivedAsync;
dataPlaneBridge.ClipboardTextReceived -= OnClipboardTextReceivedAsync;
await dataPlaneBridge.DisposeAsync().ConfigureAwait(false);
await protocolEngine.DisposeAsync().ConfigureAwait(false);
_lifetime.Dispose();
}
}
@@ -0,0 +1,57 @@
namespace Rap.Rdp.Core;
public sealed record RdpSessionDescriptor(
string SessionId,
string AttachmentId,
string OrganizationId,
string ResourceId,
string WorkerId,
RdpTargetEndpoint Target,
RdpSecurityPolicy SecurityPolicy,
RdpRuntimePolicy RuntimePolicy);
public sealed record RdpTargetEndpoint(
string Host,
int Port,
string UserName,
string Password);
public sealed record RdpSecurityPolicy(
CertificateVerificationMode CertificateVerificationMode);
public enum CertificateVerificationMode
{
Strict,
Ignore
}
public sealed record RdpRuntimePolicy(
IReadOnlySet<RapChannel> AllowedChannels,
ClipboardMode ClipboardMode,
FileTransferMode FileTransferMode);
public enum RapChannel
{
Control,
Input,
Render,
Clipboard,
FileUpload,
Telemetry
}
public enum ClipboardMode
{
Disabled,
ClientToServer,
ServerToClient,
Bidirectional
}
public enum FileTransferMode
{
Disabled,
ClientToServer,
ServerToClient,
Bidirectional
}