AltHeroes Bot v2
1using System.Diagnostics.CodeAnalysis;
2using System.Text.RegularExpressions;
3using Microsoft.Extensions.Logging;
4
5namespace AltBot.Core.Models;
6
7/// <summary>
8/// Represents a Decentralized Identifier (DID)
9/// </summary>
10public class Did : IParsable<Did>
11{
12 //private static readonly ILogger<Did>? _logger;
13 private const int MaxLength = 2048;
14
15 // Internal constructor for EF Core
16 internal Did(string value)
17 {
18 Value = value;
19 }
20
21 public string Value { get; }
22
23 /// <summary>
24 /// Creates a new Did instance after validating the input string
25 /// </summary>
26 /// <param name="rawDid">The raw DID string to validate</param>
27 /// <returns>A new Did instance if valid, null otherwise</returns>
28 public static Did? Create(string rawDid)
29 {
30 return ValidateDid(rawDid) ? new Did(rawDid) : null;
31 }
32
33 // For use when the Did is known to be valid (e.g., loading from database)
34 public static Did Load(string rawDid)
35 {
36 return new Did(rawDid);
37 }
38
39 private static bool ValidateDid(string did)
40 {
41 if (string.IsNullOrWhiteSpace(did))
42 {
43 //_logger?.LogError("DID cannot be null or empty");
44 return false;
45 }
46
47 var parts = did.Split(':');
48 if (parts.Length != 3)
49 {
50 //_logger?.LogError("DID requires prefix, method, and method-specific content");
51 return false;
52 }
53
54 if (parts[0] != "did")
55 {
56 //_logger?.LogError("DID must start with 'did' prefix");
57 return false;
58 };
59
60 // Basic method name validation
61 if (parts[1] is not "plc" and not "web")
62 {
63 //_logger?.LogError("DID method must be 'plc' or 'web'");
64 return false;
65 }
66
67 if (did.Length > MaxLength)
68 {
69 //_logger?.LogError("DID is too long ({MaxLength} chars max)", MaxLength);
70 return false;
71 }
72
73 return true;
74 }
75
76 public static Did Parse(string s, IFormatProvider? provider)
77 {
78 if (TryParse(s, provider, out var result))
79 {
80 return result;
81 }
82 throw new FormatException($"Unable to parse DID: {s}");
83 }
84
85 public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Did result)
86 {
87 if (s != null && ValidateDid(s))
88 {
89 result = new Did(s);
90 return true;
91 }
92 result = null;
93 return false;
94 }
95
96 public override string ToString() => Value;
97
98 public override bool Equals(object? obj)
99 {
100 if (obj is Did other)
101 {
102 return Value.Equals(other.Value, StringComparison.Ordinal);
103 }
104 return false;
105 }
106
107 public override int GetHashCode() => Value.GetHashCode(StringComparison.Ordinal);
108
109 public static implicit operator string(Did did) => did.Value;
110
111 public static explicit operator Did(string s) => Parse(s, null);
112
113 public static bool operator ==(Did? left, Did? right)
114 {
115 if (ReferenceEquals(left, right))
116 {
117 return true;
118 }
119
120 if (left is null || right is null)
121 {
122 return false;
123 }
124
125 return left.Equals(right);
126 }
127
128 public static bool operator !=(Did? left, Did? right) => !(left == right);
129}