InMemoryResourceCollection.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using RackPeek.Domain.Resources;
  2. using RackPeek.Domain.Resources.Models;
  3. using RackPeek.Domain.Resources.Services;
  4. using RackPeek.Domain.Resources.SystemResources;
  5. namespace RackPeek.Domain.Persistence;
  6. public sealed class InMemoryResourceCollection(IEnumerable<Resource>? seed = null) : IResourceCollection
  7. {
  8. private readonly object _lock = new();
  9. private readonly List<Resource> _resources = seed?.ToList() ?? [];
  10. public IReadOnlyList<Hardware> HardwareResources
  11. {
  12. get
  13. {
  14. lock (_lock)
  15. return _resources.OfType<Hardware>().ToList();
  16. }
  17. }
  18. public IReadOnlyList<SystemResource> SystemResources
  19. {
  20. get
  21. {
  22. lock (_lock)
  23. return _resources.OfType<SystemResource>().ToList();
  24. }
  25. }
  26. public IReadOnlyList<Service> ServiceResources
  27. {
  28. get
  29. {
  30. lock (_lock)
  31. return _resources.OfType<Service>().ToList();
  32. }
  33. }
  34. public Task<bool> Exists(string name)
  35. {
  36. lock (_lock)
  37. {
  38. return Task.FromResult(_resources.Exists(r =>
  39. r.Name.Equals(name, StringComparison.OrdinalIgnoreCase)));
  40. }
  41. }
  42. public Task LoadAsync()
  43. => Task.CompletedTask;
  44. public Task<IReadOnlyList<Resource>> GetByTagAsync(string name)
  45. {
  46. lock (_lock)
  47. return Task.FromResult<IReadOnlyList<Resource>>(_resources.Where(r => r.Tags.Contains(name)).ToList());
  48. }
  49. public Task<Dictionary<string, int>> GetTagsAsync()
  50. {
  51. lock (_lock)
  52. {
  53. var result = _resources
  54. .Where(r => r.Tags != null)
  55. .SelectMany(r => r.Tags!) // flatten all tag arrays
  56. .Where(t => !string.IsNullOrWhiteSpace(t))
  57. .GroupBy(t => t)
  58. .ToDictionary(g => g.Key, g => g.Count());
  59. return Task.FromResult(result);
  60. }
  61. }
  62. public Task AddAsync(Resource resource)
  63. {
  64. lock (_lock)
  65. {
  66. if (_resources.Any(r =>
  67. r.Name.Equals(resource.Name, StringComparison.OrdinalIgnoreCase)))
  68. throw new InvalidOperationException($"'{resource.Name}' already exists.");
  69. resource.Kind = GetKind(resource);
  70. _resources.Add(resource);
  71. }
  72. return Task.CompletedTask;
  73. }
  74. public Task UpdateAsync(Resource resource)
  75. {
  76. lock (_lock)
  77. {
  78. var index = _resources.FindIndex(r =>
  79. r.Name.Equals(resource.Name, StringComparison.OrdinalIgnoreCase));
  80. if (index == -1)
  81. throw new InvalidOperationException("Not found.");
  82. resource.Kind = GetKind(resource);
  83. _resources[index] = resource;
  84. }
  85. return Task.CompletedTask;
  86. }
  87. public Task DeleteAsync(string name)
  88. {
  89. lock (_lock)
  90. {
  91. _resources.RemoveAll(r =>
  92. r.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
  93. }
  94. return Task.CompletedTask;
  95. }
  96. public Resource? GetByName(string name)
  97. {
  98. lock (_lock)
  99. {
  100. return _resources.FirstOrDefault(r =>
  101. r.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
  102. }
  103. }
  104. private static string GetKind(Resource resource) => resource switch
  105. {
  106. Server => "Server",
  107. Switch => "Switch",
  108. Firewall => "Firewall",
  109. Router => "Router",
  110. Desktop => "Desktop",
  111. Laptop => "Laptop",
  112. AccessPoint => "AccessPoint",
  113. Ups => "Ups",
  114. SystemResource => "System",
  115. Service => "Service",
  116. _ => throw new InvalidOperationException(
  117. $"Unknown resource type: {resource.GetType().Name}")
  118. };
  119. }