ServiceSubnetsUseCase.cs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. using RackPeek.Domain.Persistence;
  2. using RackPeek.Domain.Resources.Services.Networking;
  3. namespace RackPeek.Domain.Resources.Services.UseCases;
  4. public class ServiceSubnetsUseCase(IResourceCollection repo) : IUseCase {
  5. public async Task<ServiceSubnetsResult> ExecuteAsync(string? cidr, int? prefix, CancellationToken token) {
  6. IReadOnlyList<Service> services = await repo.GetAllOfTypeAsync<Service>();
  7. // If CIDR is provided → filter mode
  8. if (cidr is not null) {
  9. Cidr parsed;
  10. try {
  11. parsed = Cidr.Parse(cidr);
  12. }
  13. catch {
  14. return ServiceSubnetsResult.InvalidCidr(cidr);
  15. }
  16. var matches = services
  17. .Where(s => s.Network?.Ip != null)
  18. .Where(s => parsed.Contains(IpHelper.ToUInt32(s.Network!.Ip!)))
  19. .Select(s => new ServiceSummary(
  20. s.Name,
  21. s.Network!.Ip!,
  22. s.RunsOn))
  23. .ToList();
  24. return ServiceSubnetsResult.FromServices(matches, parsed.ToString());
  25. }
  26. // No CIDR → subnet discovery mode
  27. var effectivePrefix = prefix ?? 24;
  28. var mask = IpHelper.MaskFromPrefix(effectivePrefix);
  29. var groups = services
  30. .Where(s => s.Network?.Ip != null)
  31. .Select(s => IpHelper.ToUInt32(s.Network!.Ip!))
  32. .GroupBy(ip => ip & mask)
  33. .Select(g => new SubnetSummary(
  34. $"{IpHelper.ToIp(g.Key)}/{effectivePrefix}",
  35. g.Count()))
  36. .OrderBy(s => s.Cidr)
  37. .ToList();
  38. return ServiceSubnetsResult.FromSubnets(groups);
  39. }
  40. }
  41. public record SubnetSummary(string Cidr, int Count);
  42. public record ServiceSummary(string Name, string Ip, List<string>? RunsOn);
  43. public class ServiceSubnetsResult {
  44. public bool IsInvalidCidr { get; private set; }
  45. public string? InvalidCidrValue { get; private set; }
  46. public string? FilteredCidr { get; private set; }
  47. public List<SubnetSummary> Subnets { get; private set; } = new();
  48. public List<ServiceSummary> Services { get; private set; } = new();
  49. public static ServiceSubnetsResult InvalidCidr(string cidr) =>
  50. new() { IsInvalidCidr = true, InvalidCidrValue = cidr };
  51. public static ServiceSubnetsResult FromSubnets(List<SubnetSummary> subnets) => new() { Subnets = subnets };
  52. public static ServiceSubnetsResult FromServices(List<ServiceSummary> services, string cidr) =>
  53. new() { Services = services, FilteredCidr = cidr };
  54. }