mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
Split remaining service routes
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
namespace DorkNet.Contracts;
|
||||
|
||||
public static class DorkNetRouteOwnership
|
||||
{
|
||||
private const string AdminHost = "admin";
|
||||
|
||||
private static readonly DorkNetRouteGroup[] ServiceRouteGroups =
|
||||
[
|
||||
new(
|
||||
ServiceNames.Identity,
|
||||
["auth", "accounts"],
|
||||
[
|
||||
"/.well-known",
|
||||
"/account",
|
||||
"/api/account",
|
||||
"/api/auth",
|
||||
"/api/createaccount",
|
||||
"/api/platformlogin",
|
||||
"/api/playerreputation",
|
||||
"/api/players",
|
||||
"/api/relationships",
|
||||
"/api/settings",
|
||||
"/cachedlogin",
|
||||
"/connect",
|
||||
"/eac",
|
||||
"/parentalcontrol",
|
||||
"/photon",
|
||||
"/profileimage",
|
||||
"/settings",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Rooms,
|
||||
["rooms", "match", "discovery", "lists", "roomcomments", "roomieintegrations", "studio"],
|
||||
[
|
||||
"/api/activities",
|
||||
"/api/curatedroomplaylists",
|
||||
"/api/gameconfigs",
|
||||
"/api/gameconfigurations",
|
||||
"/api/gamesessions",
|
||||
"/api/leaderboard",
|
||||
"/api/playerelo",
|
||||
"/api/playlists",
|
||||
"/api/roomkeys",
|
||||
"/api/rooms",
|
||||
"/api/royale",
|
||||
"/discover",
|
||||
"/featuredrooms",
|
||||
"/goto",
|
||||
"/hot_rooms",
|
||||
"/hot_roomsandplaylists",
|
||||
"/invite",
|
||||
"/playlists",
|
||||
"/player",
|
||||
"/room",
|
||||
"/roominstance",
|
||||
"/rooms",
|
||||
"/roomsandplaylists",
|
||||
"/roomserver",
|
||||
"/search_rooms",
|
||||
"/search_roomsandplaylists",
|
||||
"/v1/find",
|
||||
"/v1/join",
|
||||
"/v1/leave",
|
||||
"/v1/session",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Notify,
|
||||
["notify", "chat", "platformnotifications"],
|
||||
[
|
||||
"/api/messages",
|
||||
"/api/notification",
|
||||
"/api/offlineinvite",
|
||||
"/hub",
|
||||
"/notify",
|
||||
"/thread",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Content,
|
||||
["cdn", "data", "img", "storage", "strings-cdn", "videos"],
|
||||
[
|
||||
"/api/images",
|
||||
"/api/photos",
|
||||
"/config",
|
||||
"/data",
|
||||
"/img",
|
||||
"/invention",
|
||||
"/upload",
|
||||
"/video",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Social,
|
||||
["clubs"],
|
||||
[
|
||||
"/announcements",
|
||||
"/api/announcement",
|
||||
"/api/clubreporting",
|
||||
"/api/communityboard",
|
||||
"/api/groups",
|
||||
"/api/playercheer",
|
||||
"/api/playerevents",
|
||||
"/api/playersubscriptions",
|
||||
"/club",
|
||||
"/members",
|
||||
"/subscription",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Commerce,
|
||||
["commerce", "econ"],
|
||||
[
|
||||
"/api/avatar",
|
||||
"/api/catalog",
|
||||
"/api/compatibility",
|
||||
"/api/consumables",
|
||||
"/api/equipment",
|
||||
"/api/gamerewards",
|
||||
"/api/inventions",
|
||||
"/api/purchase",
|
||||
"/api/storefronts",
|
||||
"/commerce",
|
||||
"/econ",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Platform,
|
||||
["cards", "cms", "datacollection", "gamelogs", "geo", "leaderboard", "link", "ns", "playersettings", "strings", "thorn"],
|
||||
[
|
||||
"/api/cards",
|
||||
"/api/config",
|
||||
"/api/events",
|
||||
"/api/quickplay",
|
||||
"/api/role",
|
||||
"/api/version",
|
||||
"/api/versioncheck",
|
||||
"/motd",
|
||||
"/pageview",
|
||||
"/ping",
|
||||
"/role",
|
||||
"/strings",
|
||||
"/v1/ping",
|
||||
"/v1/player",
|
||||
"/v1/regions",
|
||||
"/v1/services",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Moderation,
|
||||
["bugreporting", "moderation"],
|
||||
[
|
||||
"/api/admin",
|
||||
"/api/banappeal",
|
||||
"/api/bugreporting",
|
||||
"/api/moderation",
|
||||
"/api/playerreporting",
|
||||
"/api/playersbanned",
|
||||
"/api/sanitize",
|
||||
"/api/testcasemanagement",
|
||||
]),
|
||||
new(
|
||||
ServiceNames.Web,
|
||||
["www", AdminHost, "feed"],
|
||||
[
|
||||
"/api/site",
|
||||
],
|
||||
IncludesApexHost: true),
|
||||
];
|
||||
|
||||
public static IReadOnlyList<DorkNetRouteGroup> RouteGroups => ServiceRouteGroups;
|
||||
|
||||
public static bool IsInfrastructurePath(string path)
|
||||
{
|
||||
return path.Equals("/healthz", StringComparison.OrdinalIgnoreCase)
|
||||
|| path.StartsWith("/internal/", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string ResolvePublicService(string? host, string path, string apexDomain)
|
||||
{
|
||||
var normalizedPath = NormalizePath(path);
|
||||
var subdomain = Subdomain(host, apexDomain);
|
||||
|
||||
if (string.Equals(subdomain, AdminHost, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ServiceNames.Web;
|
||||
}
|
||||
|
||||
foreach (var group in ServiceRouteGroups.Where(group => group.ServiceName != ServiceNames.Web))
|
||||
{
|
||||
if (MatchesHost(subdomain, group.HostSubdomains))
|
||||
{
|
||||
return group.ServiceName;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var group in ServiceRouteGroups)
|
||||
{
|
||||
if (StartsWithAny(normalizedPath, group.PathPrefixes))
|
||||
{
|
||||
return group.ServiceName;
|
||||
}
|
||||
}
|
||||
|
||||
var web = ServiceRouteGroups.First(group => group.ServiceName == ServiceNames.Web);
|
||||
if ((subdomain is null && web.IncludesApexHost) || MatchesHost(subdomain, web.HostSubdomains))
|
||||
{
|
||||
return ServiceNames.Web;
|
||||
}
|
||||
|
||||
return ServiceNames.Monolith;
|
||||
}
|
||||
|
||||
public static bool IsOwnedBy(string serviceName, string? host, string path, string apexDomain)
|
||||
{
|
||||
if (IsInfrastructurePath(path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Equals(
|
||||
ResolvePublicService(host, path, apexDomain),
|
||||
serviceName,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string? Subdomain(string? host, string apexDomain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var normalizedHost = host.Split(':', 2)[0].Trim().ToLowerInvariant();
|
||||
var normalizedApex = apexDomain.Split(':', 2)[0].Trim().ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(normalizedHost)
|
||||
|| string.IsNullOrWhiteSpace(normalizedApex)
|
||||
|| string.Equals(normalizedHost, normalizedApex, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var suffix = "." + normalizedApex;
|
||||
if (normalizedHost.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return normalizedHost[..^suffix.Length];
|
||||
}
|
||||
|
||||
var dot = normalizedHost.IndexOf('.');
|
||||
return dot > 0 ? normalizedHost[..dot] : null;
|
||||
}
|
||||
|
||||
private static bool StartsWithAny(string path, IEnumerable<string> prefixes)
|
||||
{
|
||||
foreach (var prefix in prefixes)
|
||||
{
|
||||
if (StartsWithPathSegment(path, prefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool StartsWithPathSegment(string path, string prefix)
|
||||
{
|
||||
var normalizedPath = NormalizePath(path);
|
||||
var normalizedPrefix = NormalizePath(prefix).TrimEnd('/');
|
||||
if (string.IsNullOrWhiteSpace(normalizedPrefix))
|
||||
{
|
||||
normalizedPrefix = "/";
|
||||
}
|
||||
|
||||
return normalizedPath.Equals(normalizedPrefix, StringComparison.OrdinalIgnoreCase)
|
||||
|| normalizedPath.StartsWith(normalizedPrefix + "/", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool MatchesHost(string? subdomain, IEnumerable<string> candidates)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(subdomain))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return candidates.Contains(subdomain, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string NormalizePath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
return path[0] == '/' ? path : "/" + path;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record DorkNetRouteGroup(
|
||||
string ServiceName,
|
||||
string[] HostSubdomains,
|
||||
string[] PathPrefixes,
|
||||
bool IncludesApexHost = false);
|
||||
@@ -5,7 +5,13 @@ public sealed class DorkNetServiceMapOptions
|
||||
public string Identity { get; set; } = "http://localhost:8081";
|
||||
public string Rooms { get; set; } = "http://localhost:8082";
|
||||
public string Notify { get; set; } = "http://localhost:8083";
|
||||
public string Monolith { get; set; } = "http://localhost:8084";
|
||||
public string Content { get; set; } = "http://localhost:8084";
|
||||
public string Social { get; set; } = "http://localhost:8085";
|
||||
public string Commerce { get; set; } = "http://localhost:8086";
|
||||
public string Platform { get; set; } = "http://localhost:8087";
|
||||
public string Moderation { get; set; } = "http://localhost:8088";
|
||||
public string Web { get; set; } = "http://localhost:8089";
|
||||
public string Monolith { get; set; } = "http://localhost:8090";
|
||||
|
||||
public IReadOnlyList<DorkNetServiceEndpoint> Endpoints()
|
||||
{
|
||||
@@ -14,6 +20,12 @@ public sealed class DorkNetServiceMapOptions
|
||||
new(ServiceNames.Identity, Identity),
|
||||
new(ServiceNames.Rooms, Rooms),
|
||||
new(ServiceNames.Notify, Notify),
|
||||
new(ServiceNames.Content, Content),
|
||||
new(ServiceNames.Social, Social),
|
||||
new(ServiceNames.Commerce, Commerce),
|
||||
new(ServiceNames.Platform, Platform),
|
||||
new(ServiceNames.Moderation, Moderation),
|
||||
new(ServiceNames.Web, Web),
|
||||
new(ServiceNames.Monolith, Monolith),
|
||||
];
|
||||
|
||||
|
||||
@@ -6,5 +6,11 @@ public static class ServiceNames
|
||||
public const string Identity = "identity";
|
||||
public const string Rooms = "rooms";
|
||||
public const string Notify = "notify";
|
||||
public const string Content = "content";
|
||||
public const string Social = "social";
|
||||
public const string Commerce = "commerce";
|
||||
public const string Platform = "platform";
|
||||
public const string Moderation = "moderation";
|
||||
public const string Web = "web";
|
||||
public const string Monolith = "monolith";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user