mirror of
https://github.com/Stone-Red-Code/RemoteExec.git
synced 2026-09-04 09:06:20 +02:00
Add XML docs
This commit is contained in:
@@ -1,8 +1,23 @@
|
||||
namespace RemoteExec.Server.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an individual API key configuration.
|
||||
/// </summary>
|
||||
public class ApiKeyConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the API key value.
|
||||
/// </summary>
|
||||
public required string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional description of the API key.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this API key is enabled.
|
||||
/// Default is true.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = true;
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
namespace RemoteExec.Server.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for API key authentication.
|
||||
/// </summary>
|
||||
public class AuthenticationConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the list of configured API keys.
|
||||
/// </summary>
|
||||
public List<ApiKeyConfiguration> ApiKeys { get; set; } = [];
|
||||
}
|
||||
@@ -4,10 +4,18 @@ using RemoteExec.Server.Hubs;
|
||||
|
||||
namespace RemoteExec.Server.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for handling assembly upload requests from clients.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("/")]
|
||||
public class AssemblyController(ILogger<AssemblyController> logger) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Receives an assembly binary from a client in response to an assembly request.
|
||||
/// </summary>
|
||||
/// <param name="requestId">The unique identifier for the assembly request.</param>
|
||||
/// <returns>An action result indicating success or failure.</returns>
|
||||
[HttpPost("provide-assembly")]
|
||||
public async Task<IActionResult> ProvideAssembly([FromQuery] Guid requestId)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,9 @@ using System.Text.Json;
|
||||
|
||||
namespace RemoteExec.Server.Hubs;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR hub that handles remote method execution requests from clients.
|
||||
/// </summary>
|
||||
public class RemoteExecutionHub : Hub
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, RemoteJobAssemblyLoadContext> connections = new();
|
||||
@@ -34,6 +37,12 @@ public class RemoteExecutionHub : Hub
|
||||
|
||||
private readonly ILogger<RemoteExecutionHub> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RemoteExecutionHub"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger instance.</param>
|
||||
/// <param name="executionOptions">The execution configuration options.</param>
|
||||
/// <param name="metricsOptions">The metrics configuration options.</param>
|
||||
public RemoteExecutionHub(ILogger<RemoteExecutionHub> logger, IOptions<ExecutionConfiguration> executionOptions, IOptions<MetricsConfiguration> metricsOptions)
|
||||
{
|
||||
this.logger = logger;
|
||||
@@ -49,6 +58,7 @@ public class RemoteExecutionHub : Hub
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task OnConnectedAsync()
|
||||
{
|
||||
RemoteJobAssemblyLoadContext assemblyLoadContext = new RemoteJobAssemblyLoadContext($"RemoteJob_{Guid.NewGuid()}");
|
||||
@@ -61,6 +71,7 @@ public class RemoteExecutionHub : Hub
|
||||
return base.OnConnectedAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task OnDisconnectedAsync(Exception? exception)
|
||||
{
|
||||
if (connections.TryRemove(Context.ConnectionId, out RemoteJobAssemblyLoadContext? assemblyLoadContext))
|
||||
@@ -74,6 +85,10 @@ public class RemoteExecutionHub : Hub
|
||||
return base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts processing a stream of tasks from the client.
|
||||
/// </summary>
|
||||
/// <param name="taskStream">The async enumerable stream of tasks to execute.</param>
|
||||
public async Task StartTaskStream(IAsyncEnumerable<TaskItem> taskStream)
|
||||
{
|
||||
logger.LogInformation("Starting task stream for connection {ConnectionId}", Context.ConnectionId);
|
||||
@@ -119,6 +134,11 @@ public class RemoteExecutionHub : Hub
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a single remote method request.
|
||||
/// </summary>
|
||||
/// <param name="req">The execution request.</param>
|
||||
/// <returns>The execution result.</returns>
|
||||
public async Task<RemoteExecutionResult> Execute(RemoteExecutionRequest req)
|
||||
{
|
||||
return await ExecuteTask(req);
|
||||
@@ -231,6 +251,11 @@ public class RemoteExecutionHub : Hub
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides assembly bytes to fulfill a pending assembly request.
|
||||
/// </summary>
|
||||
/// <param name="requestId">The unique identifier for the assembly request.</param>
|
||||
/// <param name="assemblyBytes">The assembly binary data.</param>
|
||||
public static async Task ProvideAssembly(Guid requestId, byte[] assemblyBytes)
|
||||
{
|
||||
if (pendingAssemblyRequests.TryRemove(requestId, out TaskCompletionSource<byte[]>? tcs))
|
||||
@@ -239,11 +264,19 @@ public class RemoteExecutionHub : Hub
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current server metrics.
|
||||
/// </summary>
|
||||
/// <returns>The current server metrics.</returns>
|
||||
public async Task<ServerMetrics> GetMetrics()
|
||||
{
|
||||
return await GetServerMetrics();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts server metrics to all connected clients if metrics have changed significantly.
|
||||
/// </summary>
|
||||
/// <param name="hubContext">The hub context for broadcasting.</param>
|
||||
public static async Task BroadcastMetricsAsync(IHubContext<RemoteExecutionHub> hubContext)
|
||||
{
|
||||
ServerMetrics metrics = await GetServerMetrics();
|
||||
|
||||
@@ -7,12 +7,21 @@ using System.Collections.Concurrent;
|
||||
|
||||
namespace RemoteExec.Server.Middleware;
|
||||
|
||||
/// <summary>
|
||||
/// Middleware that authenticates requests using API keys in the X-API-Key header.
|
||||
/// </summary>
|
||||
public class ApiKeyAuthenticationMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<ApiKeyAuthenticationMiddleware> _logger;
|
||||
private readonly ConcurrentDictionary<string, ApiKeyConfiguration> _apiKeys;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiKeyAuthenticationMiddleware"/> class.
|
||||
/// </summary>
|
||||
/// <param name="next">The next middleware in the pipeline.</param>
|
||||
/// <param name="authOptions">The authentication configuration options.</param>
|
||||
/// <param name="logger">The logger instance.</param>
|
||||
public ApiKeyAuthenticationMiddleware(
|
||||
RequestDelegate next,
|
||||
IOptionsMonitor<AuthenticationConfiguration> authOptions,
|
||||
@@ -66,6 +75,10 @@ public class ApiKeyAuthenticationMiddleware
|
||||
_logger.LogInformation("Loaded {Count} active API keys", _apiKeys.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the middleware to authenticate the request.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context for the current request.</param>
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
// Skip authentication for health checks
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace RemoteExec.Server;
|
||||
|
||||
/// <summary>
|
||||
/// An isolated assembly load context for remote job execution, allowing assemblies to be unloaded.
|
||||
/// </summary>
|
||||
public class RemoteJobAssemblyLoadContext(string name) : AssemblyLoadContext(name, true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,20 +2,34 @@
|
||||
|
||||
namespace RemoteExec.Server;
|
||||
|
||||
/// <summary>
|
||||
/// Event arguments for assembly request events.
|
||||
/// </summary>
|
||||
public class RequestAssemblyEventArgs(AssemblyName assemblyName) : EventArgs
|
||||
{
|
||||
private readonly TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
|
||||
|
||||
private Assembly? assembly = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly name being requested.
|
||||
/// </summary>
|
||||
public AssemblyName Assembly { get; } = assemblyName;
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously waits for the assembly to be provided.
|
||||
/// </summary>
|
||||
/// <returns>The assembly, or null if not provided.</returns>
|
||||
public async Task<Assembly?> GetAssemblyAsync()
|
||||
{
|
||||
await taskCompletionSource.Task;
|
||||
return assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the assembly to fulfill the request.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to provide.</param>
|
||||
public void SetAssembly(Assembly assembly)
|
||||
{
|
||||
this.assembly = assembly;
|
||||
|
||||
@@ -6,10 +6,14 @@ using RemoteExec.Server.Hubs;
|
||||
|
||||
namespace RemoteExec.Server.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Background service that periodically broadcasts server metrics to all connected clients.
|
||||
/// </summary>
|
||||
public class MetricsBroadcastService(IHubContext<RemoteExecutionHub> hubContext, ILogger<MetricsBroadcastService> logger, IOptions<MetricsConfiguration> metricsOptions) : BackgroundService
|
||||
{
|
||||
private readonly TimeSpan broadcastInterval = TimeSpan.FromMilliseconds(metricsOptions.Value.BroadcastIntervalMs);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
logger.LogInformation("Metrics broadcast service started with interval {Interval}ms", broadcastInterval.TotalMilliseconds);
|
||||
|
||||
Reference in New Issue
Block a user