From c454e87d7a8e9977d8e01befc85c987134f849d0 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Wed, 30 Jul 2025 22:36:49 +0700 Subject: [PATCH] Add new endpoint for the agent status --- .../Controllers/DataController.cs | 26 +++++++++ .../Commands/GetAgentStatusesCommand.cs | 31 +++++++++++ .../GetAgentStatusesCommandHandler.cs | 53 +++++++++++++++++++ src/Managing.Common/Enums.cs | 9 ++++ .../src/generated/ManagingApi.ts | 45 ++++++++++++++++ .../src/generated/ManagingApiTypes.ts | 10 ++++ 6 files changed, 174 insertions(+) create mode 100644 src/Managing.Application/ManageBot/Commands/GetAgentStatusesCommand.cs create mode 100644 src/Managing.Application/ManageBot/GetAgentStatusesCommandHandler.cs diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index 89ecb1b..40e7eb0 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -902,6 +902,32 @@ public class DataController : ControllerBase return Ok(response); } + /// + /// Retrieves an array of agent names and their statuses + /// + /// An array of agent status information + [HttpGet("GetAgentStatuses")] + public async Task>> GetAgentStatuses() + { + const string cacheKey = "AgentStatuses"; + + // Check if the agent statuses are already cached + var cachedStatuses = _cacheService.GetValue>(cacheKey); + + if (cachedStatuses != null) + { + return Ok(cachedStatuses); + } + + // Get all agent statuses + var agentStatuses = await _mediator.Send(new GetAgentStatusesCommand()); + + // Cache the results for 2 minutes + _cacheService.SaveValue(cacheKey, agentStatuses, TimeSpan.FromMinutes(2)); + + return Ok(agentStatuses); + } + /// /// Maps a ScenarioRequest to a domain Scenario object. /// diff --git a/src/Managing.Application/ManageBot/Commands/GetAgentStatusesCommand.cs b/src/Managing.Application/ManageBot/Commands/GetAgentStatusesCommand.cs new file mode 100644 index 0000000..1799275 --- /dev/null +++ b/src/Managing.Application/ManageBot/Commands/GetAgentStatusesCommand.cs @@ -0,0 +1,31 @@ +using MediatR; +using static Managing.Common.Enums; + +namespace Managing.Application.ManageBot.Commands +{ + /// + /// Command to retrieve all agent statuses + /// + public class GetAgentStatusesCommand : IRequest> + { + public GetAgentStatusesCommand() + { + } + } + + /// + /// Response model for agent status information + /// + public class AgentStatusResponse + { + /// + /// The name of the agent + /// + public string AgentName { get; set; } + + /// + /// The status of the agent (Online if at least one strategy is running, Offline otherwise) + /// + public AgentStatus Status { get; set; } + } +} \ No newline at end of file diff --git a/src/Managing.Application/ManageBot/GetAgentStatusesCommandHandler.cs b/src/Managing.Application/ManageBot/GetAgentStatusesCommandHandler.cs new file mode 100644 index 0000000..cdb4d34 --- /dev/null +++ b/src/Managing.Application/ManageBot/GetAgentStatusesCommandHandler.cs @@ -0,0 +1,53 @@ +using Managing.Application.Abstractions; +using Managing.Application.Abstractions.Services; +using Managing.Application.ManageBot.Commands; +using MediatR; +using static Managing.Common.Enums; + +namespace Managing.Application.ManageBot +{ + /// + /// Handler for retrieving all agent statuses + /// + public class GetAgentStatusesCommandHandler : IRequestHandler> + { + private readonly IBotService _botService; + private readonly IAccountService _accountService; + + public GetAgentStatusesCommandHandler(IBotService botService, IAccountService accountService) + { + _botService = botService; + _accountService = accountService; + } + + public Task> Handle(GetAgentStatusesCommand request, + CancellationToken cancellationToken) + { + var result = new List(); + var allActiveBots = _botService.GetActiveBots(); + + // Group bots by user and determine status + var agentGroups = allActiveBots + .Where(bot => bot.User != null) + .GroupBy(bot => bot.User) + .ToList(); + + foreach (var agentGroup in agentGroups) + { + var user = agentGroup.Key; + var bots = agentGroup.ToList(); + + // Determine agent status: Online if at least one strategy is running, Offline otherwise + var agentStatus = bots.Any(bot => bot.GetStatus() == BotStatus.Up.ToString()) ? AgentStatus.Online : AgentStatus.Offline; + + result.Add(new AgentStatusResponse + { + AgentName = user.AgentName, + Status = agentStatus + }); + } + + return Task.FromResult(result); + } + } +} \ No newline at end of file diff --git a/src/Managing.Common/Enums.cs b/src/Managing.Common/Enums.cs index 5d87bf9..ede4162 100644 --- a/src/Managing.Common/Enums.cs +++ b/src/Managing.Common/Enums.cs @@ -464,4 +464,13 @@ public static class Enums Twors, Uniform } + + /// + /// Agent status for indicating if an agent is active or not + /// + public enum AgentStatus + { + Offline, + Online + } } \ No newline at end of file diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 30e5cd7..56f9d6a 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -2059,6 +2059,41 @@ export class DataClient extends AuthorizedApiBase { } return Promise.resolve(null as any); } + + data_GetAgentStatuses(): Promise { + let url_ = this.baseUrl + "/Data/GetAgentStatuses"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.http.fetch(url_, transformedOptions_); + }).then((_response: Response) => { + return this.processData_GetAgentStatuses(_response); + }); + } + + protected processData_GetAgentStatuses(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as AgentStatusResponse[]; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } } export class MoneyManagementClient extends AuthorizedApiBase { @@ -4498,6 +4533,16 @@ export interface BestAgentsResponse { totalPages?: number; } +export interface AgentStatusResponse { + agentName?: string | null; + status?: AgentStatus; +} + +export enum AgentStatus { + Offline = "Offline", + Online = "Online", +} + export interface ScenarioViewModel { name: string; indicators: IndicatorViewModel[]; diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index eb4de46..e59240c 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -1023,6 +1023,16 @@ export interface BestAgentsResponse { totalPages?: number; } +export interface AgentStatusResponse { + agentName?: string | null; + status?: AgentStatus; +} + +export enum AgentStatus { + Offline = "Offline", + Online = "Online", +} + export interface ScenarioViewModel { name: string; indicators: IndicatorViewModel[];