using System.Collections.Concurrent; using AMREZ.EOP.Abstractions.Applications.Tenancy; using AMREZ.EOP.Domain.Shared.Tenancy; namespace AMREZ.EOP.Infrastructures.Tenancy; /// /// ศูนย์รวม mapping แบบไดนามิก: /// - Tenants: slug/key -> TenantContext /// - DomainToTenant: custom-domain -> tenantKey /// - BaseDomains: ชุดโดเมนแพลตฟอร์มที่รองรับรูปแบบ *.basedomain (รองรับหลายอันได้) /// คุณสามารถเติม/แก้ไขระหว่างรันงานผ่าน Admin API หรือ job reload จาก DB ได้เลย /// public sealed class TenantMap { private readonly ConcurrentDictionary _tenants = new(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentDictionary _domainToTenant = new(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentDictionary _baseDomains = new(StringComparer.OrdinalIgnoreCase); // ====== Query ====== public bool TryGetBySlug(string slug, out ITenantContext ctx) { if (_tenants.TryGetValue(slug, out var t)) { ctx = t; return true; } ctx = null!; return false; } public bool TryGetByDomain(string domain, out ITenantContext ctx) { if (_domainToTenant.TryGetValue(domain, out var key) && _tenants.TryGetValue(key, out var t)) { ctx = t; return true; } ctx = null!; return false; } public bool TryGetBaseDomainFor(string host, out string? baseDomain) { foreach (var kv in _baseDomains.Keys) { var bd = kv; if (host.EndsWith(bd, StringComparison.OrdinalIgnoreCase) && !host.Equals(bd, StringComparison.OrdinalIgnoreCase)) { baseDomain = bd; return true; } } baseDomain = null; return false; } // ====== Admin / Reload ====== public void UpsertTenant(string key, TenantContext ctx) => _tenants[key] = ctx; public bool RemoveTenant(string key) => _tenants.TryRemove(key, out _); public void MapDomain(string domain, string tenantKey) => _domainToTenant[domain.Trim().ToLowerInvariant()] = tenantKey; public bool UnmapDomain(string domain) => _domainToTenant.TryRemove(domain.Trim().ToLowerInvariant(), out _); public void AddBaseDomain(string baseDomain) => _baseDomains[baseDomain.Trim().ToLowerInvariant()] = 1; public bool RemoveBaseDomain(string baseDomain) => _baseDomains.TryRemove(baseDomain.Trim().ToLowerInvariant(), out _); }