using System.Text.Json; using FinlyticAssets.Services; using FinlyticCore.Entities.Assets; using FinlyticCore.Models.Assets; using FinlyticCore.Util; namespace FinlyticAssets.Util; /// /// Represents a managed MQTT client acting as a server-side RPC provider within the asset microservice. /// It subscribes to request topics, processes incoming JSON payloads via the database service, and publishes /// the requested asset entities back to the corresponding response topic. /// public class AssetsMqttClient : ManagedMqttClient { private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// The logger used to record connection, error, and status messages. /// The database service used for querying and validating assets. public AssetsMqttClient(ILogger logger, IServiceScopeFactory scopeFactory) : base(logger) { _scopeFactory = scopeFactory; _logger = logger; } /// /// Invoked automatically once the connection to the MQTT broker is successfully established or restored. /// Registers the required wildcard subscriptions for incoming asset validation and search requests. /// /// A representing the asynchronous subscription operation. protected override async Task OnConnectedAsync() { await SubscribeAsync("services/request/assets_Get/#"); await SubscribeAsync("services/request/assets_Search/#"); } /// /// Processes incoming messages on the subscribed topics, executes the corresponding database query, /// and publishes the result to the response topic while preserving the correlation ID. /// /// The MQTT topic on which the message was received. /// The incoming message as a UTF-8 encoded JSON string. /// A representing the asynchronous message processing operation. protected override async Task OnMessageReceivedAsync(string topic, string payload) { var segments = topic.Split('/'); if (segments.Length < 4) return; var channel = segments[2]; var correlationId = segments[3]; try { List responseData = []; using var scope = _scopeFactory.CreateScope(); var dbService = scope.ServiceProvider.GetRequiredService(); switch (channel) { case "assets_Get": var validReq = JsonSerializer.Deserialize(payload); if (validReq != null) { responseData = await dbService.GetValidAssetsByIsinAsync(validReq.Isin); } break; case "assets_Search": var searchReq = JsonSerializer.Deserialize(payload); if (searchReq != null) { responseData = await dbService.FindAffectedActiveAssetsAsync(searchReq.SearchQuery); } break; } { string responseTopic = $"services/response/{channel}/{correlationId}"; await PublishAsync(responseTopic, responseData.ToDtoList()); } } catch (Exception ex) { OnError(ex); } } }