docs: add XML doc comments across src + Sister Projects section in CLAUDE.md
Bulk CommentChecker pass: fills in <param>/<inheritdoc> tags on public APIs across all 23 src/ projects so the doc-coverage gate is green. Also adds a Sister Projects section to CLAUDE.md pointing at the MxAccess Gateway and OtOpcUa sibling repos, and gitignores local credential captures (*login*.txt) and the wonder-app-vd03 deploy/ artifacts.
This commit is contained in:
@@ -58,6 +58,7 @@ public sealed class NotificationForwarder
|
||||
/// Returns <c>true</c> when central accepts the notification; throws on a
|
||||
/// non-accepted ack or an Ask timeout/failure so the engine retries.
|
||||
/// </summary>
|
||||
/// <param name="message">The buffered store-and-forward message to deliver to central.</param>
|
||||
public async Task<bool> DeliverAsync(StoreAndForwardMessage message)
|
||||
{
|
||||
// An unreadable payload cannot be fixed by retrying — park it (return false),
|
||||
@@ -148,6 +149,10 @@ public sealed class NotificationForwarder
|
||||
/// </summary>
|
||||
public sealed class NotificationForwardException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new exception with the specified message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message describing the forward failure.</param>
|
||||
public NotificationForwardException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ public class ParkedMessageHandlerActor : ReceiveActor
|
||||
private readonly StoreAndForwardService _service;
|
||||
private readonly string _siteId;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the actor and registers message handlers for query, retry, and discard operations.
|
||||
/// </summary>
|
||||
/// <param name="service">The store-and-forward service used to execute parked-message operations.</param>
|
||||
/// <param name="siteId">The site identifier this actor manages parked messages for.</param>
|
||||
public ParkedMessageHandlerActor(StoreAndForwardService service, string siteId)
|
||||
{
|
||||
_service = service;
|
||||
|
||||
@@ -17,6 +17,9 @@ public class ReplicationService
|
||||
private readonly ILogger<ReplicationService> _logger;
|
||||
private Func<ReplicationOperation, Task>? _replicationHandler;
|
||||
|
||||
/// <summary>Initializes a new instance of <see cref="ReplicationService"/>.</summary>
|
||||
/// <param name="options">Store-and-forward configuration options.</param>
|
||||
/// <param name="logger">Logger instance.</param>
|
||||
public ReplicationService(
|
||||
StoreAndForwardOptions options,
|
||||
ILogger<ReplicationService> logger)
|
||||
@@ -29,6 +32,7 @@ public class ReplicationService
|
||||
/// Sets the handler for forwarding replication operations to the standby node.
|
||||
/// Typically wraps Akka Tell to the standby's replication actor.
|
||||
/// </summary>
|
||||
/// <param name="handler">The async delegate that forwards each replication operation to the standby.</param>
|
||||
public void SetReplicationHandler(Func<ReplicationOperation, Task> handler)
|
||||
{
|
||||
_replicationHandler = handler;
|
||||
@@ -37,6 +41,7 @@ public class ReplicationService
|
||||
/// <summary>
|
||||
/// WP-11: Replicates an enqueue operation to standby (fire-and-forget).
|
||||
/// </summary>
|
||||
/// <param name="message">The message that was enqueued on the active node.</param>
|
||||
public void ReplicateEnqueue(StoreAndForwardMessage message)
|
||||
{
|
||||
if (!_options.ReplicationEnabled || _replicationHandler == null) return;
|
||||
@@ -50,6 +55,7 @@ public class ReplicationService
|
||||
/// <summary>
|
||||
/// WP-11: Replicates a remove operation to standby (fire-and-forget).
|
||||
/// </summary>
|
||||
/// <param name="messageId">The identifier of the message to remove from the standby buffer.</param>
|
||||
public void ReplicateRemove(string messageId)
|
||||
{
|
||||
if (!_options.ReplicationEnabled || _replicationHandler == null) return;
|
||||
@@ -63,6 +69,7 @@ public class ReplicationService
|
||||
/// <summary>
|
||||
/// WP-11: Replicates a park operation to standby (fire-and-forget).
|
||||
/// </summary>
|
||||
/// <param name="message">The message that was parked on the active node.</param>
|
||||
public void ReplicatePark(StoreAndForwardMessage message)
|
||||
{
|
||||
if (!_options.ReplicationEnabled || _replicationHandler == null) return;
|
||||
@@ -79,6 +86,7 @@ public class ReplicationService
|
||||
/// carried message reflects the active node's post-requeue state (Pending,
|
||||
/// retry_count = 0) so the standby's copy can be brought into sync.
|
||||
/// </summary>
|
||||
/// <param name="message">The message in its post-requeue (Pending, retry_count=0) state.</param>
|
||||
public void ReplicateRequeue(StoreAndForwardMessage message)
|
||||
{
|
||||
if (!_options.ReplicationEnabled || _replicationHandler == null) return;
|
||||
@@ -93,6 +101,8 @@ public class ReplicationService
|
||||
/// WP-11: Applies a replicated operation received from the active node.
|
||||
/// Used by the standby node to keep its SQLite in sync.
|
||||
/// </summary>
|
||||
/// <param name="operation">The replication operation to apply.</param>
|
||||
/// <param name="storage">The standby node's store-and-forward storage to update.</param>
|
||||
public async Task ApplyReplicatedOperationAsync(
|
||||
ReplicationOperation operation,
|
||||
StoreAndForwardStorage storage)
|
||||
|
||||
@@ -7,6 +7,10 @@ namespace ScadaLink.StoreAndForward;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers Store-and-Forward services including storage, the delivery service, and the replication service.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection to register into.</param>
|
||||
public static IServiceCollection AddStoreAndForward(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<StoreAndForwardStorage>(sp =>
|
||||
@@ -58,6 +62,10 @@ public static class ServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Store-and-Forward Akka actor bindings. Actor creation is handled by the Host during actor system startup.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection to register into.</param>
|
||||
public static IServiceCollection AddStoreAndForwardActors(this IServiceCollection services)
|
||||
{
|
||||
// Akka actor registration handled by Host component during actor system startup
|
||||
|
||||
@@ -74,6 +74,15 @@ public class StoreAndForwardService
|
||||
/// </summary>
|
||||
public event Action<string, StoreAndForwardCategory, string>? OnActivity;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StoreAndForwardService.
|
||||
/// </summary>
|
||||
/// <param name="storage">The storage backend for buffered messages.</param>
|
||||
/// <param name="options">Configuration options.</param>
|
||||
/// <param name="logger">Logger instance.</param>
|
||||
/// <param name="replication">Optional replication service for standby synchronization.</param>
|
||||
/// <param name="cachedCallObserver">Optional observer for cached call lifecycle events.</param>
|
||||
/// <param name="siteId">The site identifier this service belongs to.</param>
|
||||
public StoreAndForwardService(
|
||||
StoreAndForwardStorage storage,
|
||||
StoreAndForwardOptions options,
|
||||
@@ -95,6 +104,8 @@ public class StoreAndForwardService
|
||||
/// <c>_deliveryHandlers</c> field documentation for the true/false/throws contract,
|
||||
/// which applies identically on the immediate and retry paths.
|
||||
/// </summary>
|
||||
/// <param name="category">The message category to handle.</param>
|
||||
/// <param name="handler">The delivery handler function.</param>
|
||||
public void RegisterDeliveryHandler(
|
||||
StoreAndForwardCategory category,
|
||||
Func<StoreAndForwardMessage, Task<bool>> handler)
|
||||
@@ -562,6 +573,10 @@ public class StoreAndForwardService
|
||||
/// <summary>
|
||||
/// WP-12: Gets parked messages for central query (Pattern 8).
|
||||
/// </summary>
|
||||
/// <param name="category">Optional category filter, or null for all categories.</param>
|
||||
/// <param name="pageNumber">The page number (1-based).</param>
|
||||
/// <param name="pageSize">The page size.</param>
|
||||
/// <returns>A tuple of parked messages and the total count.</returns>
|
||||
public async Task<(List<StoreAndForwardMessage> Messages, int TotalCount)> GetParkedMessagesAsync(
|
||||
StoreAndForwardCategory? category = null,
|
||||
int pageNumber = 1,
|
||||
@@ -579,6 +594,8 @@ public class StoreAndForwardService
|
||||
/// StoreAndForward-017: the activity-log entry carries the message's true
|
||||
/// category rather than a hard-coded one.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The identifier of the message to retry.</param>
|
||||
/// <returns>True if successfully retried, false otherwise.</returns>
|
||||
public async Task<bool> RetryParkedMessageAsync(string messageId)
|
||||
{
|
||||
var success = await _storage.RetryParkedMessageAsync(messageId);
|
||||
@@ -607,6 +624,8 @@ public class StoreAndForwardService
|
||||
/// StoreAndForward-017: the activity-log entry carries the message's true
|
||||
/// category rather than a hard-coded one.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The identifier of the message to discard.</param>
|
||||
/// <returns>True if successfully discarded, false otherwise.</returns>
|
||||
public async Task<bool> DiscardParkedMessageAsync(string messageId)
|
||||
{
|
||||
// Capture the category before the row is deleted so the activity log is
|
||||
@@ -625,6 +644,7 @@ public class StoreAndForwardService
|
||||
/// <summary>
|
||||
/// WP-14: Gets buffer depth by category for health reporting.
|
||||
/// </summary>
|
||||
/// <returns>A dictionary of buffer depths by category.</returns>
|
||||
public async Task<Dictionary<StoreAndForwardCategory, int>> GetBufferDepthAsync()
|
||||
{
|
||||
return await _storage.GetBufferDepthByCategoryAsync();
|
||||
@@ -633,6 +653,8 @@ public class StoreAndForwardService
|
||||
/// <summary>
|
||||
/// WP-13: Gets count of S&F messages for a given instance (for verifying survival on deletion).
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The instance name to query.</param>
|
||||
/// <returns>The number of messages originating from the instance.</returns>
|
||||
public async Task<int> GetMessageCountForInstanceAsync(string instanceName)
|
||||
{
|
||||
return await _storage.GetMessageCountByOriginInstanceAsync(instanceName);
|
||||
@@ -644,6 +666,8 @@ public class StoreAndForwardService
|
||||
/// notification still in transit at the site — central reports it not-found while
|
||||
/// the S&F buffer still holds it, which is the site-local <c>Forwarding</c> state.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The message identifier.</param>
|
||||
/// <returns>The message, or null if not found.</returns>
|
||||
public async Task<StoreAndForwardMessage?> GetMessageByIdAsync(string messageId)
|
||||
{
|
||||
return await _storage.GetMessageByIdAsync(messageId);
|
||||
|
||||
@@ -27,6 +27,11 @@ public class StoreAndForwardStorage
|
||||
private readonly string _connectionString;
|
||||
private readonly ILogger<StoreAndForwardStorage> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="StoreAndForwardStorage"/> with the given SQLite connection string.
|
||||
/// </summary>
|
||||
/// <param name="connectionString">SQLite connection string for the store-and-forward database.</param>
|
||||
/// <param name="logger">Logger for diagnostics.</param>
|
||||
public StoreAndForwardStorage(string connectionString, ILogger<StoreAndForwardStorage> logger)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
@@ -139,6 +144,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// WP-9: Enqueues a new message with Pending status.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to enqueue.</param>
|
||||
public async Task EnqueueAsync(StoreAndForwardMessage message)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -209,6 +215,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// WP-10: Updates a message after a delivery attempt.
|
||||
/// </summary>
|
||||
/// <param name="message">The message with updated retry count, status, and last error.</param>
|
||||
public async Task UpdateMessageAsync(StoreAndForwardMessage message)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -246,6 +253,8 @@ public class StoreAndForwardStorage
|
||||
/// the status the sweep observed closes the sweep-vs-management race rather than
|
||||
/// relying only on the in-process overlapping-sweep guard.
|
||||
/// </summary>
|
||||
/// <param name="message">The message with the updated values to persist.</param>
|
||||
/// <param name="expectedStatus">The status the row must currently have for the update to proceed.</param>
|
||||
public async Task<bool> UpdateMessageIfStatusAsync(
|
||||
StoreAndForwardMessage message,
|
||||
StoreAndForwardMessageStatus expectedStatus)
|
||||
@@ -277,6 +286,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// WP-10: Removes a successfully delivered message.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The id of the message to remove.</param>
|
||||
public async Task RemoveMessageAsync(string messageId)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -298,6 +308,9 @@ public class StoreAndForwardStorage
|
||||
/// inconsistent with the returned page (flickering totals / off-by-one page math
|
||||
/// in the paginated UI).
|
||||
/// </summary>
|
||||
/// <param name="category">Optional category filter; null returns parked messages from all categories.</param>
|
||||
/// <param name="pageNumber">1-based page number.</param>
|
||||
/// <param name="pageSize">Maximum number of messages to return per page.</param>
|
||||
public async Task<(List<StoreAndForwardMessage> Messages, int TotalCount)> GetParkedMessagesAsync(
|
||||
StoreAndForwardCategory? category = null,
|
||||
int pageNumber = 1,
|
||||
@@ -352,6 +365,7 @@ public class StoreAndForwardStorage
|
||||
/// interval relative to the original (pre-park) attempt — "try immediately" only
|
||||
/// by accident, and a long interval would instead delay the operator's retry.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The id of the parked message to move back to Pending.</param>
|
||||
public async Task<bool> RetryParkedMessageAsync(string messageId)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -374,6 +388,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// WP-12: Permanently discards a parked message.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The id of the parked message to discard.</param>
|
||||
public async Task<bool> DiscardParkedMessageAsync(string messageId)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -420,6 +435,7 @@ public class StoreAndForwardStorage
|
||||
/// WP-13: Verifies messages are NOT deleted when an instance is deleted.
|
||||
/// Returns the count of messages for a given origin instance.
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The origin instance name to count messages for.</param>
|
||||
public async Task<int> GetMessageCountByOriginInstanceAsync(string instanceName)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -438,6 +454,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// Gets a message by ID.
|
||||
/// </summary>
|
||||
/// <param name="messageId">The id of the message to retrieve.</param>
|
||||
public async Task<StoreAndForwardMessage?> GetMessageByIdAsync(string messageId)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
@@ -473,6 +490,7 @@ public class StoreAndForwardStorage
|
||||
/// <summary>
|
||||
/// Gets total message count by status.
|
||||
/// </summary>
|
||||
/// <param name="status">The status to filter by.</param>
|
||||
public async Task<int> GetMessageCountByStatusAsync(StoreAndForwardMessageStatus status)
|
||||
{
|
||||
await using var connection = new SqliteConnection(_connectionString);
|
||||
|
||||
Reference in New Issue
Block a user