mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 12:16:03 +08:00
feat: auto fetch remote hotfix.
This commit is contained in:
@@ -17,6 +17,7 @@ public class HttpServerConfig
|
||||
public string PublicAddress { get; set; } = "127.0.0.1";
|
||||
public int Port { get; set; } = 443;
|
||||
public bool UseSSL { get; set; } = false;
|
||||
public bool UseFetchRemoteHotfix { get; set; } = false;
|
||||
|
||||
public string GetDisplayAddress()
|
||||
{
|
||||
|
||||
@@ -21,6 +21,14 @@ public class DownloadUrlConfig
|
||||
public string IfixUrl { get; set; } = "";
|
||||
}
|
||||
|
||||
public static class GateWayBaseUrl
|
||||
{
|
||||
public const string CNBETA = "https://beta-release01-cn.bhsr.com/query_gateway";
|
||||
public const string CNPROD = "https://prod-gf-cn-dp01.bhsr.com/query_gateway";
|
||||
public const string OSBETA = "https://beta-release01-asia.starrails.com/query_gateway";
|
||||
public const string OSPROD = "https://prod-official-asia-dp01.starrails.com/query_gateway";
|
||||
}
|
||||
|
||||
public static class BaseUrl
|
||||
{
|
||||
public const string CN = "https://autopatchcn.bhsr.com/";
|
||||
|
||||
@@ -2,11 +2,12 @@ namespace EggLink.DanhengServer.Util;
|
||||
|
||||
public static class HttpNetwork
|
||||
{
|
||||
public static async ValueTask<(int, string?)> SendGetRequest(string url)
|
||||
public static async ValueTask<(int, string?)> SendGetRequest(string url, int timeout = 30)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(timeout);
|
||||
var response = await client.GetAsync(url);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return ((int)response.StatusCode, content);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using EggLink.DanhengServer.Util;
|
||||
using EggLink.DanhengServer.WebServer.Handler;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using EggLink.DanhengServer.WebServer.Request;
|
||||
namespace EggLink.DanhengServer.WebServer.Controllers;
|
||||
|
||||
[ApiController]
|
||||
@@ -9,7 +9,7 @@ namespace EggLink.DanhengServer.WebServer.Controllers;
|
||||
public class GateServerRoutes
|
||||
{
|
||||
[HttpGet("/query_gateway")]
|
||||
public async ValueTask<ContentResult> QueryGateway([FromQuery] string version)
|
||||
public async ValueTask<ContentResult> QueryGateway([FromQuery] GateWayRequest req)
|
||||
{
|
||||
if (!ConfigManager.Config.ServerOption.ServerConfig.RunGateway)
|
||||
return new ContentResult
|
||||
@@ -20,7 +20,7 @@ public class GateServerRoutes
|
||||
await ValueTask.CompletedTask;
|
||||
return new ContentResult
|
||||
{
|
||||
Content = new QueryGatewayHandler(version).Data,
|
||||
Content = new QueryGatewayHandler(req).Data,
|
||||
StatusCode = 200,
|
||||
ContentType = "plain/text; charset=utf-8"
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ using EggLink.DanhengServer.Enums;
|
||||
using EggLink.DanhengServer.Internationalization;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using EggLink.DanhengServer.WebServer.Request;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace EggLink.DanhengServer.WebServer.Handler;
|
||||
@@ -14,7 +15,7 @@ internal partial class QueryGatewayHandler
|
||||
public static Logger Logger = new("GatewayServer");
|
||||
public string Data;
|
||||
|
||||
public QueryGatewayHandler(string version)
|
||||
public QueryGatewayHandler(GateWayRequest req)
|
||||
{
|
||||
var config = ConfigManager.Config;
|
||||
|
||||
@@ -39,7 +40,7 @@ internal partial class QueryGatewayHandler
|
||||
|
||||
// Auto separate CN/OS prefix
|
||||
var region = ConfigManager.Hotfix.Region;
|
||||
if (region == BaseRegionEnum.None) _ = Enum.TryParse(version[..2], out region);
|
||||
if (region == BaseRegionEnum.None) _ = Enum.TryParse(req.version[..2], out region);
|
||||
var baseUrl = region switch
|
||||
{
|
||||
BaseRegionEnum.CN => BaseUrl.CN,
|
||||
@@ -47,21 +48,15 @@ internal partial class QueryGatewayHandler
|
||||
_ => BaseUrl.OS
|
||||
};
|
||||
|
||||
// Separate CN/OS hotfix by client
|
||||
var ver = VersionRegex().Replace(version, "");
|
||||
ConfigManager.Hotfix.HotfixData.TryGetValue(ver, out var urls);
|
||||
if (urls != null)
|
||||
var remoteHotfixSuccess = false;
|
||||
if (ConfigManager.Config.HttpServer.UseFetchRemoteHotfix)
|
||||
{
|
||||
if (urls.AssetBundleUrl != "")
|
||||
gateServer.AssetBundleUrl = baseUrl + urls.AssetBundleUrl;
|
||||
if (urls.ExAssetBundleUrl != "")
|
||||
gateServer.ExAssetBundleUrl = baseUrl + urls.ExAssetBundleUrl;
|
||||
if (urls.ExResourceUrl != "")
|
||||
gateServer.ExResourceUrl = baseUrl + urls.ExResourceUrl;
|
||||
if (urls.LuaUrl != "")
|
||||
gateServer.LuaUrl = baseUrl + urls.LuaUrl;
|
||||
if (urls.IfixUrl != "")
|
||||
gateServer.IfixUrl = baseUrl + urls.IfixUrl;
|
||||
remoteHotfixSuccess = FetchRemoteHotfix(req, region, gateServer).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (!remoteHotfixSuccess)
|
||||
{
|
||||
UseLocalHotfix(req, region, baseUrl, gateServer);
|
||||
}
|
||||
|
||||
if (!ResourceManager.IsLoaded) gateServer.Retcode = 2;
|
||||
@@ -70,6 +65,132 @@ internal partial class QueryGatewayHandler
|
||||
Data = Convert.ToBase64String(gateServer.ToByteArray());
|
||||
}
|
||||
|
||||
private async Task<bool> FetchRemoteHotfix(GateWayRequest req, BaseRegionEnum region, GateServer gateServer)
|
||||
{
|
||||
try
|
||||
{
|
||||
var gatewayUrl = GetGatewayUrlByVersion(req.version);
|
||||
// build query params
|
||||
var queryParams = new Dictionary<string, string>
|
||||
{
|
||||
["version"] = req.version,
|
||||
["t"] = req.t,
|
||||
["uid"] = req.uid,
|
||||
["language_type"] = req.language_type,
|
||||
["platform_type"] = req.platform_type,
|
||||
["dispatch_seed"] = req.dispatch_seed,
|
||||
["channel_id"] = req.channel_id,
|
||||
["sub_channel_id"] = req.sub_channel_id,
|
||||
["is_need_url"] = req.is_need_url,
|
||||
["game_version"] = req.game_version,
|
||||
["account_type"] = req.account_type,
|
||||
["account_uid"] = req.account_uid
|
||||
};
|
||||
|
||||
var queryString = string.Join("&", queryParams.Select(kv => $"{kv.Key}={kv.Value}"));
|
||||
var fullUrl = $"{gatewayUrl}?{queryString}";
|
||||
|
||||
var (statusCode, response) = await HttpNetwork.SendGetRequest(fullUrl, 5);
|
||||
|
||||
if (statusCode == 200 && !string.IsNullOrEmpty(response))
|
||||
{
|
||||
try
|
||||
{
|
||||
// parse base64 response
|
||||
var bytes = Convert.FromBase64String(response);
|
||||
var remoteGateServer = GateServer.Parser.ParseFrom(bytes);
|
||||
|
||||
// check if remote hotfix urls are valid, if not use local configuration
|
||||
if (!string.IsNullOrEmpty(remoteGateServer.AssetBundleUrl))
|
||||
{
|
||||
gateServer.AssetBundleUrl = remoteGateServer.AssetBundleUrl;
|
||||
gateServer.ExAssetBundleUrl = remoteGateServer.ExAssetBundleUrl;
|
||||
gateServer.ExResourceUrl = remoteGateServer.ExResourceUrl;
|
||||
gateServer.LuaUrl = remoteGateServer.LuaUrl;
|
||||
gateServer.IfixUrl = remoteGateServer.IfixUrl;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn("Remote hotfix return empty, fall back to local hotfix");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warn($"Failed to parse remote hotfix response: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn($"Remote hotfix request failed with status: {statusCode}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warn($"Remote hotfix fetch failed: {ex.Message}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UseLocalHotfix(GateWayRequest req, BaseRegionEnum region, string baseUrl, GateServer gateServer)
|
||||
{
|
||||
var ver = VersionRegex().Replace(req.version, "");
|
||||
ConfigManager.Hotfix.HotfixData.TryGetValue(ver, out var urls);
|
||||
|
||||
if (urls != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(urls.AssetBundleUrl))
|
||||
gateServer.AssetBundleUrl = baseUrl + urls.AssetBundleUrl;
|
||||
if (!string.IsNullOrEmpty(urls.ExAssetBundleUrl))
|
||||
gateServer.ExAssetBundleUrl = baseUrl + urls.ExAssetBundleUrl;
|
||||
if (!string.IsNullOrEmpty(urls.ExResourceUrl))
|
||||
gateServer.ExResourceUrl = baseUrl + urls.ExResourceUrl;
|
||||
if (!string.IsNullOrEmpty(urls.LuaUrl))
|
||||
gateServer.LuaUrl = baseUrl + urls.LuaUrl;
|
||||
if (!string.IsNullOrEmpty(urls.IfixUrl))
|
||||
gateServer.IfixUrl = baseUrl + urls.IfixUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn($"No local hotfix found for version: {ver}");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetGatewayUrlByVersion(string version)
|
||||
{
|
||||
if (version.Contains("CNPROD", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GateWayBaseUrl.CNPROD;
|
||||
}
|
||||
else if (version.Contains("CNBETA", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GateWayBaseUrl.CNBETA;
|
||||
}
|
||||
else if (version.Contains("OSPROD", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GateWayBaseUrl.OSPROD;
|
||||
}
|
||||
else if (version.Contains("OSBETA", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GateWayBaseUrl.OSBETA;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default fallback based on region prefix
|
||||
var region = version[..2];
|
||||
if (region.Equals("CN", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GateWayBaseUrl.CNPROD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GateWayBaseUrl.OSPROD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"BETA|PROD|CECREATION|Android|Win|iOS")]
|
||||
private static partial Regex VersionRegex();
|
||||
}
|
||||
17
WebServer/Request/GateWayRequest.cs
Normal file
17
WebServer/Request/GateWayRequest.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace EggLink.DanhengServer.WebServer.Request;
|
||||
|
||||
public class GateWayRequest
|
||||
{
|
||||
public string version { get; set; } = "";
|
||||
public string t { get; set; } = "";
|
||||
public string uid { get; set; } = "";
|
||||
public string language_type { get; set; } = "";
|
||||
public string platform_type { get; set; } = "";
|
||||
public string dispatch_seed { get; set; } = "";
|
||||
public string channel_id { get; set; } = "";
|
||||
public string sub_channel_id { get; set; } = "";
|
||||
public string is_need_url { get; set; } = "";
|
||||
public string game_version { get; set; } = "";
|
||||
public string account_type { get; set; } = "";
|
||||
public string account_uid { get; set; } = "";
|
||||
}
|
||||
Reference in New Issue
Block a user