diff --git a/RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj b/RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj index 87def2e..1fc93c2 100644 --- a/RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj +++ b/RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj @@ -4,6 +4,7 @@ net10.0 enable enable + True diff --git a/RemoteExec.Client.DependencyInjection/RemoteExecutorServiceCollectionExtensions.cs b/RemoteExec.Client.DependencyInjection/RemoteExecutorServiceCollectionExtensions.cs index 89dac4a..fe885b4 100644 --- a/RemoteExec.Client.DependencyInjection/RemoteExecutorServiceCollectionExtensions.cs +++ b/RemoteExec.Client.DependencyInjection/RemoteExecutorServiceCollectionExtensions.cs @@ -4,8 +4,18 @@ using Microsoft.Extensions.Logging; namespace RemoteExec.Client.DependencyInjection; +/// +/// Extension methods for registering RemoteExecutor with dependency injection. +/// public static class RemoteExecutorServiceCollectionExtensions { + /// + /// Adds a singleton RemoteExecutor to the service collection. + /// + /// The service collection to add to. + /// The URLs of the remote execution servers. + /// An optional action to configure the executor options. + /// The service collection for chaining. public static IServiceCollection AddRemoteExecutor(this IServiceCollection services, string[] urls, Action? configure = null) { RemoteExecutorOptions options = new RemoteExecutorOptions(); diff --git a/RemoteExec.Client/AsyncManualResetEvent.cs b/RemoteExec.Client/AsyncManualResetEvent.cs index aff7d68..ff6db55 100644 --- a/RemoteExec.Client/AsyncManualResetEvent.cs +++ b/RemoteExec.Client/AsyncManualResetEvent.cs @@ -1,9 +1,16 @@ namespace RemoteExec.Client; +/// +/// An async-compatible manual reset event that can be awaited. +/// internal class AsyncManualResetEvent { private volatile TaskCompletionSource _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously); + /// + /// Initializes a new instance of the class. + /// + /// If true, the event is initially signaled. public AsyncManualResetEvent(bool initialState) { if (initialState) @@ -12,16 +19,27 @@ internal class AsyncManualResetEvent } } + /// + /// Asynchronously waits for the event to be signaled. + /// + /// A cancellation token to cancel the wait operation. + /// A task that completes when the event is signaled. public Task WaitAsync(CancellationToken ct) { return _tcs.Task.WaitAsync(ct); } + /// + /// Sets the event to a signaled state, releasing all waiting tasks. + /// public void Set() { _ = _tcs.TrySetResult(true); } + /// + /// Resets the event to an unsignaled state. + /// public void Reset() { while (true) diff --git a/RemoteExec.Client/Exceptions/MaxRetriesException.cs b/RemoteExec.Client/Exceptions/MaxRetriesException.cs index 4c96cce..ac73874 100644 --- a/RemoteExec.Client/Exceptions/MaxRetriesException.cs +++ b/RemoteExec.Client/Exceptions/MaxRetriesException.cs @@ -1,5 +1,8 @@ namespace RemoteExec.Client.Exceptions; +/// +/// Exception thrown when a task exceeds the maximum number of retry attempts. +/// public class MaxRetriesException(string message) : Exception(message) { } diff --git a/RemoteExec.Client/Exceptions/RemoteExecutionException.cs b/RemoteExec.Client/Exceptions/RemoteExecutionException.cs index c2fe637..7ecfdc5 100644 --- a/RemoteExec.Client/Exceptions/RemoteExecutionException.cs +++ b/RemoteExec.Client/Exceptions/RemoteExecutionException.cs @@ -1,5 +1,8 @@ namespace RemoteExec.Client.Exceptions; +/// +/// Exception thrown when a remote method execution fails on the server. +/// public class RemoteExecutionException(string message) : Exception(message) { } \ No newline at end of file diff --git a/RemoteExec.Client/ILoadBalancingStrategy.cs b/RemoteExec.Client/ILoadBalancingStrategy.cs index 10cbc78..ee743f1 100644 --- a/RemoteExec.Client/ILoadBalancingStrategy.cs +++ b/RemoteExec.Client/ILoadBalancingStrategy.cs @@ -1,6 +1,14 @@ namespace RemoteExec.Client; +/// +/// Defines a strategy for selecting a server from a pool of available servers for task distribution. +/// public interface ILoadBalancingStrategy { + /// + /// Selects the most appropriate server from the available servers based on the strategy's logic. + /// + /// The collection of available servers to choose from. + /// The selected server, or null if no suitable server is found. ServerConnection? SelectServer(IEnumerable availableServers); } diff --git a/RemoteExec.Client/LoadBalancingStrategies/ResourceAwareStrategy.cs b/RemoteExec.Client/LoadBalancingStrategies/ResourceAwareStrategy.cs index 2b3c08d..5e3f131 100644 --- a/RemoteExec.Client/LoadBalancingStrategies/ResourceAwareStrategy.cs +++ b/RemoteExec.Client/LoadBalancingStrategies/ResourceAwareStrategy.cs @@ -1,7 +1,11 @@ namespace RemoteExec.Client.LoadBalancingStrategies; +/// +/// A load balancing strategy that selects servers based on CPU usage, active tasks, and backlog. +/// internal class ResourceAwareStrategy : ILoadBalancingStrategy { + /// public ServerConnection? SelectServer(IEnumerable availableServers) { return availableServers.MinBy(s => diff --git a/RemoteExec.Client/RemoteExec.Client.csproj b/RemoteExec.Client/RemoteExec.Client.csproj index 16bc780..c43c42c 100644 --- a/RemoteExec.Client/RemoteExec.Client.csproj +++ b/RemoteExec.Client/RemoteExec.Client.csproj @@ -4,6 +4,7 @@ net10.0 enable enable + True diff --git a/RemoteExec.Client/RemoteExecLoggerProvider.cs b/RemoteExec.Client/RemoteExecLoggerProvider.cs index f8ae5f6..50eb7a3 100644 --- a/RemoteExec.Client/RemoteExecLoggerProvider.cs +++ b/RemoteExec.Client/RemoteExecLoggerProvider.cs @@ -2,21 +2,33 @@ namespace RemoteExec.Client; +/// +/// Logger provider that forwards log messages to an existing logger instance. +/// internal class RemoteExecLoggerProvider : ILoggerProvider { private bool disposedValue; private readonly ILogger logger; + /// + /// Initializes a new instance of the class. + /// + /// The logger instance to forward messages to. public RemoteExecLoggerProvider(ILogger logger) { this.logger = logger; } + /// public ILogger CreateLogger(string categoryName) { return logger; } + /// + /// Disposes the logger provider. + /// + /// True if disposing managed resources. protected virtual void Dispose(bool disposing) { if (!disposedValue) @@ -26,6 +38,7 @@ internal class RemoteExecLoggerProvider : ILoggerProvider } } + /// public void Dispose() { Dispose(disposing: true); diff --git a/RemoteExec.Client/RemoteExecutor.ConnectionManagement.cs b/RemoteExec.Client/RemoteExecutor.ConnectionManagement.cs index 787c68a..9e4ac1d 100644 --- a/RemoteExec.Client/RemoteExecutor.ConnectionManagement.cs +++ b/RemoteExec.Client/RemoteExecutor.ConnectionManagement.cs @@ -10,6 +10,10 @@ namespace RemoteExec.Client; public partial class RemoteExecutor { + /// + /// Starts the remote executor, connecting to all configured servers and beginning task distribution. + /// + /// A cancellation token to cancel the operation. public async Task StartAsync(CancellationToken cancellationToken = default) { // Dispose previous cancellation token source if exists @@ -40,6 +44,10 @@ public partial class RemoteExecutor distributorTask = Task.Run(() => DistributorLoop(distributorCts.Token), distributorCts.Token); } + /// + /// Stops the remote executor, disconnecting from all servers and stopping task distribution. + /// + /// A cancellation token to cancel the operation. public async Task StopAsync(CancellationToken cancellationToken = default) { logger.LogInformation("Stopping RemoteExecutor..."); diff --git a/RemoteExec.Client/RemoteExecutor.cs b/RemoteExec.Client/RemoteExecutor.cs index 8a4631a..db4fafe 100644 --- a/RemoteExec.Client/RemoteExecutor.cs +++ b/RemoteExec.Client/RemoteExecutor.cs @@ -11,6 +11,9 @@ using System.Text.Json; namespace RemoteExec.Client; +/// +/// Manages remote execution of static methods across one or more server connections with load balancing and fault tolerance. +/// public partial class RemoteExecutor : IAsyncDisposable { private readonly BlockingCollection globalQueue; @@ -27,20 +30,45 @@ public partial class RemoteExecutor : IAsyncDisposable private bool disposedValue; + /// + /// Occurs when server metrics are updated. + /// public event EventHandler? MetricsUpdated; + /// + /// Initializes a new instance of the class with a single server URL. + /// + /// The URL of the remote server. + /// An action to configure the executor options. public RemoteExecutor(string url, Action configure) : this([url], NullLogger.Instance, configure) { } + /// + /// Initializes a new instance of the class with a single server URL and logger. + /// + /// The URL of the remote server. + /// The logger instance. + /// An action to configure the executor options. public RemoteExecutor(string url, ILogger logger, Action configure) : this([url], logger, configure) { } + /// + /// Initializes a new instance of the class with multiple server URLs. + /// + /// The URLs of the remote servers. + /// An action to configure the executor options. public RemoteExecutor(string[] urls, Action configure) : this(urls, NullLogger.Instance, configure) { } + /// + /// Initializes a new instance of the class with multiple server URLs and logger. + /// + /// The URLs of the remote servers. + /// The logger instance. + /// An action to configure the executor options. public RemoteExecutor(string[] urls, ILogger logger, Action configure) { this.logger = logger; @@ -53,6 +81,12 @@ public partial class RemoteExecutor : IAsyncDisposable InitializeServers(urls); } + /// + /// Initializes a new instance of the class with preconfigured options. + /// + /// The URLs of the remote servers. + /// The executor options. + /// The logger instance. public RemoteExecutor(string[] urls, RemoteExecutorOptions options, ILogger logger) { this.logger = logger; @@ -99,6 +133,10 @@ public partial class RemoteExecutor : IAsyncDisposable } } + /// + /// Gets the current metrics for all connected servers. + /// + /// A dictionary mapping server IDs to their metrics. public Dictionary GetCurrentServerMetrics() { return servers @@ -107,6 +145,15 @@ public partial class RemoteExecutor : IAsyncDisposable .ToDictionary(metrics => metrics!.ServerId, metrics => metrics!); } + /// + /// Executes a delegate remotely and returns the strongly-typed result. + /// + /// The delegate type. + /// The return type. + /// The delegate to execute. + /// A cancellation token to cancel the operation. + /// The arguments to pass to the method. + /// The result of the remote execution. public async Task ExecuteAsync(TDelegate @delegate, CancellationToken cancellationToken, params object[] args) where TDelegate : Delegate { object? execResult = await ExecuteAsync(@delegate, cancellationToken, args); @@ -125,11 +172,29 @@ public partial class RemoteExecutor : IAsyncDisposable } } + /// + /// Executes a delegate remotely and returns the strongly-typed result. + /// + /// The delegate type. + /// The return type. + /// The delegate to execute. + /// The arguments to pass to the method. + /// The result of the remote execution. public async Task ExecuteAsync(TDelegate @delegate, params object[] args) where TDelegate : Delegate { return await ExecuteAsync(@delegate, CancellationToken.None, args); } + /// + /// Executes a delegate remotely and returns the result. + /// + /// The delegate type. + /// The delegate to execute. Must be a static method. + /// A cancellation token to cancel the operation. + /// The arguments to pass to the method. + /// The result of the remote execution. + /// Thrown when the delegate is not a static method or uses a dynamic assembly. + /// Thrown when the remote execution fails. public async Task ExecuteAsync(T @delegate, CancellationToken cancellationToken, params object[] args) where T : Delegate { MethodInfo method = @delegate.Method; @@ -189,11 +254,22 @@ public partial class RemoteExecutor : IAsyncDisposable } } + /// + /// Executes a delegate remotely and returns the result. + /// + /// The delegate type. + /// The delegate to execute. Must be a static method. + /// The arguments to pass to the method. + /// The result of the remote execution. public Task ExecuteAsync(T @delegate, params object[] args) where T : Delegate { return ExecuteAsync(@delegate, CancellationToken.None, args); } + /// + /// Asynchronously disposes the executor and its resources. + /// + /// True if disposing managed resources. protected virtual async Task DisposeAsync(bool disposing) { if (!disposedValue) @@ -220,6 +296,7 @@ public partial class RemoteExecutor : IAsyncDisposable } } + /// public async ValueTask DisposeAsync() { await DisposeAsync(disposing: true); diff --git a/RemoteExec.Client/RemoteExecutorOptions.cs b/RemoteExec.Client/RemoteExecutorOptions.cs index ac45613..ceaf274 100644 --- a/RemoteExec.Client/RemoteExecutorOptions.cs +++ b/RemoteExec.Client/RemoteExecutorOptions.cs @@ -2,22 +2,49 @@ namespace RemoteExec.Client; +/// +/// Configuration options for the remote executor client. +/// public class RemoteExecutorOptions { + /// + /// Gets or sets the load balancing strategy used to select servers for task execution. + /// Default is . + /// public ILoadBalancingStrategy Strategy { get; set; } = new ResourceAwareStrategy(); + /// + /// Gets or sets the API key used for authenticating with remote servers. + /// public string ApiKey { get; set; } = string.Empty; - // How long to wait for a result before throwing a TimeoutException + /// + /// Gets or sets the maximum time to wait for a task result before throwing a TimeoutException. + /// Default is 5 minutes. + /// public TimeSpan ExecutionTimeout { get; set; } = TimeSpan.FromMinutes(5); - // Backoff settings for server reconnections + /// + /// Gets or sets the initial delay before attempting to reconnect to a disconnected server. + /// Default is 5 seconds. + /// public TimeSpan ServerReconnectInitialDelay { get; set; } = TimeSpan.FromSeconds(5); + + /// + /// Gets or sets the maximum delay between server reconnection attempts. + /// Default is 60 seconds. + /// public TimeSpan ServerReconnectMaxDelay { get; set; } = TimeSpan.FromSeconds(60); - // Reliability: How many times a task can be requeued before failing + /// + /// Gets or sets the maximum number of times a failed task can be requeued before failing permanently. + /// Default is 3. + /// public int MaxTaskRetries { get; set; } = 3; - // Capacity: Stop accepting Execute calls if the global queue is too full + /// + /// Gets or sets the maximum number of tasks that can be queued globally before blocking new execute calls. + /// Default is 1000. + /// public int GlobalQueueCapacity { get; set; } = 1000; } diff --git a/RemoteExec.Client/ServerConnection.cs b/RemoteExec.Client/ServerConnection.cs index 27aa4ad..ffe479c 100644 --- a/RemoteExec.Client/ServerConnection.cs +++ b/RemoteExec.Client/ServerConnection.cs @@ -6,11 +6,33 @@ using System.Threading.Channels; namespace RemoteExec.Client; +/// +/// Represents a connection to a remote execution server, including communication channels and metrics. +/// public class ServerConnection(HubConnection connection, HttpClient httpClient) { + /// + /// Gets the SignalR hub connection to the server. + /// public HubConnection Connection { get; } = connection; + + /// + /// Gets the HTTP client for REST API communication with the server. + /// public HttpClient HttpClient { get; } = httpClient; + + /// + /// Gets the channel used to queue tasks for this server. + /// public Channel TaskChannel { get; } = Channel.CreateUnbounded(); + + /// + /// Gets or sets the current metrics for this server. + /// public ServerMetrics? Metrics { get; set; } + + /// + /// Gets or sets the handler for connection closed events. + /// public Func? ClosedEventHandler { get; set; } } \ No newline at end of file diff --git a/RemoteExec.Client/ServerMetricsUpdatedEventArgs.cs b/RemoteExec.Client/ServerMetricsUpdatedEventArgs.cs index db4ad46..7e859f9 100644 --- a/RemoteExec.Client/ServerMetricsUpdatedEventArgs.cs +++ b/RemoteExec.Client/ServerMetricsUpdatedEventArgs.cs @@ -4,8 +4,18 @@ using RemoteExec.Shared; namespace RemoteExec.Client; +/// +/// Provides data for the event. +/// public class ServerMetricsUpdatedEventArgs(HubConnection connection, ServerMetrics metrics) : EventArgs { + /// + /// Gets the hub connection associated with the metrics update. + /// public HubConnection Connection { get; } = connection; + + /// + /// Gets the updated server metrics. + /// public ServerMetrics Metrics { get; } = metrics; } diff --git a/RemoteExec.Server/Configuration/ApiKeyConfiguration.cs b/RemoteExec.Server/Configuration/ApiKeyConfiguration.cs index 6ea8e49..039e0fc 100644 --- a/RemoteExec.Server/Configuration/ApiKeyConfiguration.cs +++ b/RemoteExec.Server/Configuration/ApiKeyConfiguration.cs @@ -1,8 +1,23 @@ namespace RemoteExec.Server.Configuration; +/// +/// Represents an individual API key configuration. +/// public class ApiKeyConfiguration { + /// + /// Gets or sets the API key value. + /// public required string Key { get; set; } + + /// + /// Gets or sets an optional description of the API key. + /// public string? Description { get; set; } + + /// + /// Gets or sets whether this API key is enabled. + /// Default is true. + /// public bool Enabled { get; set; } = true; } \ No newline at end of file diff --git a/RemoteExec.Server/Configuration/AuthenticationConfiguration.cs b/RemoteExec.Server/Configuration/AuthenticationConfiguration.cs index 057f9bf..c8f4322 100644 --- a/RemoteExec.Server/Configuration/AuthenticationConfiguration.cs +++ b/RemoteExec.Server/Configuration/AuthenticationConfiguration.cs @@ -1,6 +1,12 @@ namespace RemoteExec.Server.Configuration; +/// +/// Configuration for API key authentication. +/// public class AuthenticationConfiguration { + /// + /// Gets or sets the list of configured API keys. + /// public List ApiKeys { get; set; } = []; } \ No newline at end of file diff --git a/RemoteExec.Server/Controllers/AssemblyController.cs b/RemoteExec.Server/Controllers/AssemblyController.cs index ecb0097..ef06e8f 100644 --- a/RemoteExec.Server/Controllers/AssemblyController.cs +++ b/RemoteExec.Server/Controllers/AssemblyController.cs @@ -4,10 +4,18 @@ using RemoteExec.Server.Hubs; namespace RemoteExec.Server.Controllers; +/// +/// Controller for handling assembly upload requests from clients. +/// [ApiController] [Route("/")] public class AssemblyController(ILogger logger) : ControllerBase { + /// + /// Receives an assembly binary from a client in response to an assembly request. + /// + /// The unique identifier for the assembly request. + /// An action result indicating success or failure. [HttpPost("provide-assembly")] public async Task ProvideAssembly([FromQuery] Guid requestId) { diff --git a/RemoteExec.Server/Hubs/RemoteExecutionHub.cs b/RemoteExec.Server/Hubs/RemoteExecutionHub.cs index d48629c..ee796ad 100644 --- a/RemoteExec.Server/Hubs/RemoteExecutionHub.cs +++ b/RemoteExec.Server/Hubs/RemoteExecutionHub.cs @@ -11,6 +11,9 @@ using System.Text.Json; namespace RemoteExec.Server.Hubs; +/// +/// SignalR hub that handles remote method execution requests from clients. +/// public class RemoteExecutionHub : Hub { private static readonly ConcurrentDictionary connections = new(); @@ -34,6 +37,12 @@ public class RemoteExecutionHub : Hub private readonly ILogger logger; + /// + /// Initializes a new instance of the class. + /// + /// The logger instance. + /// The execution configuration options. + /// The metrics configuration options. public RemoteExecutionHub(ILogger logger, IOptions executionOptions, IOptions metricsOptions) { this.logger = logger; @@ -49,6 +58,7 @@ public class RemoteExecutionHub : Hub } } + /// public override Task OnConnectedAsync() { RemoteJobAssemblyLoadContext assemblyLoadContext = new RemoteJobAssemblyLoadContext($"RemoteJob_{Guid.NewGuid()}"); @@ -61,6 +71,7 @@ public class RemoteExecutionHub : Hub return base.OnConnectedAsync(); } + /// 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); } + /// + /// Starts processing a stream of tasks from the client. + /// + /// The async enumerable stream of tasks to execute. public async Task StartTaskStream(IAsyncEnumerable taskStream) { logger.LogInformation("Starting task stream for connection {ConnectionId}", Context.ConnectionId); @@ -119,6 +134,11 @@ public class RemoteExecutionHub : Hub } } + /// + /// Executes a single remote method request. + /// + /// The execution request. + /// The execution result. public async Task Execute(RemoteExecutionRequest req) { return await ExecuteTask(req); @@ -231,6 +251,11 @@ public class RemoteExecutionHub : Hub } } + /// + /// Provides assembly bytes to fulfill a pending assembly request. + /// + /// The unique identifier for the assembly request. + /// The assembly binary data. public static async Task ProvideAssembly(Guid requestId, byte[] assemblyBytes) { if (pendingAssemblyRequests.TryRemove(requestId, out TaskCompletionSource? tcs)) @@ -239,11 +264,19 @@ public class RemoteExecutionHub : Hub } } + /// + /// Gets the current server metrics. + /// + /// The current server metrics. public async Task GetMetrics() { return await GetServerMetrics(); } + /// + /// Broadcasts server metrics to all connected clients if metrics have changed significantly. + /// + /// The hub context for broadcasting. public static async Task BroadcastMetricsAsync(IHubContext hubContext) { ServerMetrics metrics = await GetServerMetrics(); diff --git a/RemoteExec.Server/Middleware/ApiKeyAuthenticationMiddleware.cs b/RemoteExec.Server/Middleware/ApiKeyAuthenticationMiddleware.cs index 8869ae1..2778c8d 100644 --- a/RemoteExec.Server/Middleware/ApiKeyAuthenticationMiddleware.cs +++ b/RemoteExec.Server/Middleware/ApiKeyAuthenticationMiddleware.cs @@ -7,12 +7,21 @@ using System.Collections.Concurrent; namespace RemoteExec.Server.Middleware; +/// +/// Middleware that authenticates requests using API keys in the X-API-Key header. +/// public class ApiKeyAuthenticationMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly ConcurrentDictionary _apiKeys; + /// + /// Initializes a new instance of the class. + /// + /// The next middleware in the pipeline. + /// The authentication configuration options. + /// The logger instance. public ApiKeyAuthenticationMiddleware( RequestDelegate next, IOptionsMonitor authOptions, @@ -66,6 +75,10 @@ public class ApiKeyAuthenticationMiddleware _logger.LogInformation("Loaded {Count} active API keys", _apiKeys.Count); } + /// + /// Invokes the middleware to authenticate the request. + /// + /// The HTTP context for the current request. public async Task InvokeAsync(HttpContext context) { // Skip authentication for health checks diff --git a/RemoteExec.Server/RemoteJobAssemblyLoadContext.cs b/RemoteExec.Server/RemoteJobAssemblyLoadContext.cs index 92399c6..c9c9d10 100644 --- a/RemoteExec.Server/RemoteJobAssemblyLoadContext.cs +++ b/RemoteExec.Server/RemoteJobAssemblyLoadContext.cs @@ -2,6 +2,9 @@ namespace RemoteExec.Server; +/// +/// An isolated assembly load context for remote job execution, allowing assemblies to be unloaded. +/// public class RemoteJobAssemblyLoadContext(string name) : AssemblyLoadContext(name, true) { } diff --git a/RemoteExec.Server/RequestAssemblyEventArgs.cs b/RemoteExec.Server/RequestAssemblyEventArgs.cs index 2a319ee..05b0600 100644 --- a/RemoteExec.Server/RequestAssemblyEventArgs.cs +++ b/RemoteExec.Server/RequestAssemblyEventArgs.cs @@ -2,20 +2,34 @@ namespace RemoteExec.Server; +/// +/// Event arguments for assembly request events. +/// public class RequestAssemblyEventArgs(AssemblyName assemblyName) : EventArgs { private readonly TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); private Assembly? assembly = null; + /// + /// Gets the assembly name being requested. + /// public AssemblyName Assembly { get; } = assemblyName; + /// + /// Asynchronously waits for the assembly to be provided. + /// + /// The assembly, or null if not provided. public async Task GetAssemblyAsync() { await taskCompletionSource.Task; return assembly; } + /// + /// Sets the assembly to fulfill the request. + /// + /// The assembly to provide. public void SetAssembly(Assembly assembly) { this.assembly = assembly; diff --git a/RemoteExec.Server/Services/MetricsBroadcastService.cs b/RemoteExec.Server/Services/MetricsBroadcastService.cs index 4a720ac..13fda6d 100644 --- a/RemoteExec.Server/Services/MetricsBroadcastService.cs +++ b/RemoteExec.Server/Services/MetricsBroadcastService.cs @@ -6,10 +6,14 @@ using RemoteExec.Server.Hubs; namespace RemoteExec.Server.Services; +/// +/// Background service that periodically broadcasts server metrics to all connected clients. +/// public class MetricsBroadcastService(IHubContext hubContext, ILogger logger, IOptions metricsOptions) : BackgroundService { private readonly TimeSpan broadcastInterval = TimeSpan.FromMilliseconds(metricsOptions.Value.BroadcastIntervalMs); + /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogInformation("Metrics broadcast service started with interval {Interval}ms", broadcastInterval.TotalMilliseconds); diff --git a/RemoteExec.Shared/RemoteExecutionRequest.cs b/RemoteExec.Shared/RemoteExecutionRequest.cs index dca8ec7..704f1d5 100644 --- a/RemoteExec.Shared/RemoteExecutionRequest.cs +++ b/RemoteExec.Shared/RemoteExecutionRequest.cs @@ -1,10 +1,32 @@ namespace RemoteExec.Shared; +/// +/// Represents a request to execute a static method on a remote server. +/// public sealed class RemoteExecutionRequest { + /// + /// Gets or sets the full name of the assembly containing the method. + /// public required string AssemblyName { get; set; } + + /// + /// Gets or sets the full name of the type containing the method. + /// public required string TypeName { get; set; } + + /// + /// Gets or sets the name of the method to execute. + /// public required string MethodName { get; set; } + + /// + /// Gets or sets the assembly-qualified names of the method's parameter types. + /// public required string[] ArgumentTypes { get; set; } + + /// + /// Gets or sets the arguments to pass to the method. + /// public required object[] Arguments { get; set; } } diff --git a/RemoteExec.Shared/RemoteExecutionResult.cs b/RemoteExec.Shared/RemoteExecutionResult.cs index b069dc0..a6f04ee 100644 --- a/RemoteExec.Shared/RemoteExecutionResult.cs +++ b/RemoteExec.Shared/RemoteExecutionResult.cs @@ -1,7 +1,17 @@ namespace RemoteExec.Shared; +/// +/// Represents the result of a remote method execution. +/// public sealed class RemoteExecutionResult { + /// + /// Gets or sets the return value of the executed method, or null if the method returns void. + /// public object? Result { get; set; } + + /// + /// Gets or sets the exception message if the execution failed, or null if successful. + /// public string? Exception { get; set; } } diff --git a/RemoteExec.Shared/ServerMetrics.cs b/RemoteExec.Shared/ServerMetrics.cs index b3a2f2d..dec4ffa 100644 --- a/RemoteExec.Shared/ServerMetrics.cs +++ b/RemoteExec.Shared/ServerMetrics.cs @@ -1,12 +1,42 @@ namespace RemoteExec.Shared; +/// +/// Represents performance and status metrics for a remote execution server. +/// public sealed class ServerMetrics { + /// + /// Gets or sets the number of active client connections to the server. + /// public int ActiveConnections { get; set; } + + /// + /// Gets or sets the number of tasks currently being executed on the server. + /// public int ActiveTasks { get; set; } + + /// + /// Gets or sets the maximum number of tasks that can execute concurrently on the server. + /// public int MaxConcurrentTasks { get; set; } + + /// + /// Gets or sets the total memory usage of the server process in bytes. + /// public long TotalMemoryUsage { get; set; } + + /// + /// Gets or sets the CPU usage percentage (0-100) of the server process. + /// public double CpuUsage { get; set; } + + /// + /// Gets or sets the timestamp when these metrics were captured. + /// public DateTime Timestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the server. + /// public string ServerId { get; set; } = string.Empty; } \ No newline at end of file diff --git a/RemoteExec.Shared/TaskItem.cs b/RemoteExec.Shared/TaskItem.cs index 0965379..3535751 100644 --- a/RemoteExec.Shared/TaskItem.cs +++ b/RemoteExec.Shared/TaskItem.cs @@ -1,7 +1,17 @@ namespace RemoteExec.Shared; +/// +/// Represents a task item in the execution stream, combining a task ID with its execution request. +/// public class TaskItem { + /// + /// Gets or sets the unique identifier for this task. + /// public Guid TaskId { get; set; } + + /// + /// Gets or sets the execution request details. + /// public required RemoteExecutionRequest Request { get; set; } } \ No newline at end of file