ThrowIfInvalid.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System.ComponentModel.DataAnnotations;
  2. namespace RackPeek.Domain.Helpers;
  3. public static class ThrowIfInvalid
  4. {
  5. public static void ResourceName(string name)
  6. {
  7. if (string.IsNullOrWhiteSpace(name))
  8. throw new ValidationException("Name is required.");
  9. if (name.Length > 50)
  10. throw new ValidationException("Name is too long.");
  11. }
  12. public static void AccessPointModelName(string name)
  13. {
  14. if (string.IsNullOrWhiteSpace(name))
  15. throw new ValidationException("Model name is required.");
  16. if (name.Length > 50)
  17. throw new ValidationException("Model name is too long.");
  18. }
  19. public static void RamGb(int? value)
  20. {
  21. if (value is null)
  22. throw new ValidationException("RAM value must be specified.");
  23. if (value < 0)
  24. throw new ValidationException("RAM value must be a non negative number of gigabytes.");
  25. }
  26. #region Nics
  27. public static readonly string[] ValidNicTypes =
  28. {
  29. // Copper Ethernet
  30. "rj45",
  31. // SFP family
  32. "sfp", // 1G
  33. "sfp+", // 10G
  34. "sfp28", // 25G
  35. "sfp56", // 50G
  36. // QSFP family
  37. "qsfp+", // 40G
  38. "qsfp28", // 100G
  39. "qsfp56", // 200G
  40. "qsfp-dd", // 400G (QSFP Double Density)
  41. // OSFP (400G+)
  42. "osfp",
  43. // Legacy / niche but still seen
  44. "xfp",
  45. "cx4",
  46. // Management / special-purpose
  47. "mgmt" // Dedicated management NIC (IPMI/BMC)
  48. };
  49. public static void NicType(string nicType)
  50. {
  51. if (string.IsNullOrWhiteSpace(nicType))
  52. throw new ValidationException("NIC type is required.");
  53. var normalized = nicType.Trim().ToLowerInvariant();
  54. if (ValidNicTypes.Contains(normalized))
  55. return;
  56. var suggestions = GetNicTypeSuggestions(normalized).ToList();
  57. var message = suggestions.Any()
  58. ? $"NIC type '{nicType}' is not valid. Did you mean: {string.Join(", ", suggestions)}?"
  59. : $"NIC type '{nicType}' is not valid. Valid NIC types include rj45, sfp, sfp+, qsfp+ etc";
  60. throw new ValidationException(message);
  61. }
  62. private static IEnumerable<string> GetNicTypeSuggestions(string input)
  63. {
  64. return ValidNicTypes
  65. .Select(type => new
  66. {
  67. Type = type,
  68. Score = SimilarityScore(input, type)
  69. })
  70. .Where(x => x.Score >= 0.5)
  71. .OrderByDescending(x => x.Score)
  72. .Take(3)
  73. .Select(x => x.Type);
  74. }
  75. private static double SimilarityScore(string a, string b)
  76. {
  77. if (a == b)
  78. return 1.0;
  79. if (b.StartsWith(a) || a.StartsWith(b))
  80. return 0.9;
  81. var commonChars = a.Intersect(b).Count();
  82. return (double)commonChars / Math.Max(a.Length, b.Length);
  83. }
  84. public static void NicSpeed(int speed)
  85. {
  86. if (speed < 0)
  87. throw new ValidationException(
  88. "NIC speed must be a non negative number of gigabits per second.");
  89. }
  90. public static void NetworkSpeed(double speed)
  91. {
  92. if (speed < 0)
  93. throw new ValidationException(
  94. "Network speed must be a non negative number of gigabits per second.");
  95. }
  96. public static void NicPorts(int ports)
  97. {
  98. if (ports < 0)
  99. throw new ValidationException(
  100. "NIC port count must be a non negative integer.");
  101. }
  102. #endregion
  103. }