Files
back_cantanBuilding/Assets/Scripts/AOTScripts/GConfig.cs
2026-05-26 16:15:54 +08:00

373 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using asap.core;
using SimpleJSON;
using UnityEngine;
using UnityEngine.Networking;
public static class ConfigExtension
{
private const string defaultconfig = "9Nf/P8vm2+7Ciph2jH1QnEaHCK3cAl7lNnCJc/uxSKGVqcJgWilN3VgaC/74coHRiRpxEelC2+ia7qcjnHhA3OQN82rcVJOP24pGKrSbSgOIGbH9cCEUhdYRo5vnVgLBqlTS/c/AajowTkN59O0AYxDC7J3jq6ptLXdmuG27JYS9NXOQDkgxpzEpG7JTtczHKxhWAv+9uSzbJRCs16KeusbJX1YtNZM8wjCD9esTv4zXXMIpZPlXb86NjHiI02TakAdHo0plO+Di9n5UCC8/4+QGoKNyQgtvIkzMyoGziO4DOLy/VkfITenFv/+9DY0LmpZGa7Cog89znaYyVMTiC/3R2IefXXh04+8uqmyzeVKqh0grcU9qmz485wCoUl/TM9F8+s1Jhp/eaB/E7luOjc57Kz0Eyw2Qko7Fo+lCaRJE1uex9fB46v0LhddSHCEWw8QERmqG9KcmvG4LsyafupA8kliDzj7a7XIzGrgnNnsMxLgeYsSbNiBvXXESeeNCoqiOQTTBpk/br0QuTHTG2DRxUZZ4KM3SKZtHEZ2bZV2FUS4azFpfDXUGoc86O+xz6hAIMbdKCHyqyEeKMmHIzQI9OlIaa3KGwk+w1eFDUuq4zyTh+qGuClZynanUkfNe8mTmFtBax2f3MJHjGpXJT0VdtY/R+5ZQO0nCU30THfnryG0GURsrv6MQYiQX5hsLqG9Z72ybbbbqIR2rvE2w13DM/tqTb4i/hN0+pbeTKkUpdNIWEsR94Q==";
private static string RemoteConfigUrl { get; set; }
public static void Rest(this IConfig config)
{
RemoteConfigUrl = null;
}
public static async Task<bool> InitConfig(this IConfig config)
{
JSONNode streamingAssetConfig = null;
JSONNode persistConfig = null;
bool isSuccessLoadRemoteConfigFile = true;
if (RemoteConfigUrl == null)
{
streamingAssetConfig = GetStreamingAssetConfig();
persistConfig = GetPersistConfig();
}
if (RemoteConfigUrl == null)
{
RemoteConfigUrl = string.Format(GConstant.V_Static_Res_URL, VersionTool.PackVer);
}
JSONNode remoteConfig = await GetRemoteConfig();
if (remoteConfig == null)
{
var remoteConfigStr = Decrypt(defaultconfig);
remoteConfig = JSON.Parse(remoteConfigStr);
remoteConfig["Ver"] = VersionTool.FromLocal().ToVerString();
isSuccessLoadRemoteConfigFile = false;
}
foreach (var element in remoteConfig)
{
config.Set(element.Key, element.Value.Value);
}
if (streamingAssetConfig != null)
{
foreach (var element in streamingAssetConfig)
{
config.Set(element.Key, element.Value.Value);
}
}
if (persistConfig != null)
{
foreach (var element in persistConfig)
{
config.Set(element.Key, element.Value.Value);
}
}
config.Set(GConstant.K_Static_Res_URL, RemoteConfigUrl);
return isSuccessLoadRemoteConfigFile;
}
private static readonly float[] timeoutValues = new float[] { 1, 2, 2 };
public static async Task<JSONNode> GetRemoteConfig()
{
UnityEngine.Assertions.Assert.IsNotNull(RemoteConfigUrl, "Config is not inited");
await Awaiters.NextFrame;
var maxRetryTimes = timeoutValues.Length;
for (int retryTime = 0; retryTime < maxRetryTimes; retryTime++)
{
var rawConfig = await DoGetRawConfigUWR(timeoutValues[retryTime], retryTime, maxRetryTimes);
if (!string.IsNullOrEmpty(rawConfig))
{
Debug.Log($"<color=orange>Load remote config success {retryTime + 1}/{maxRetryTimes}</color>");
return JSON.Parse(rawConfig);
}
}
return null;
}
private static async Task<string> DoGetRawConfigUWR(float timeoutInSec, int retryTimes, int maxRetryTimes)
{
using (var req = UnityWebRequest.Get($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}"))
{
var stopwatch = new System.Diagnostics.Stopwatch();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(timeoutInSec));
var ct = cts.Token;
stopwatch.Start();
req.timeout = (int)timeoutInSec;
req.SetRequestHeader("Accept", "application/json");
var op = req.SendWebRequest();
try
{
while (!op.isDone && !ct.IsCancellationRequested)
{
await Awaiters.NextFrame;
}
ct.ThrowIfCancellationRequested();
stopwatch.Stop();
if (req.result == UnityWebRequest.Result.Success)
{
return Decrypt(req.downloadHandler.text);
}
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
e.AddContent("reason", req.result.ToString());
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
e.AddContent("error", req.error);
}
#endif // AGG
Debug.LogWarning($"Load remote config failed {req.result.ToString()} {req.error} {retryTimes + 1}/{maxRetryTimes}");
}
catch (OperationCanceledException)
{
req.Abort();
stopwatch.Stop();
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
e.AddContent("reason", "cancel");
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
e.AddContent("error", req.error ?? "cancel");
}
#endif // AGG
Debug.LogWarning($"Load remote config cancel {req.result.ToString()} {req.error} {retryTimes + 1}/{maxRetryTimes}");
}
finally
{
cts.Dispose();
}
return null;
}
}
/**
private static async Task<string> DoGetRawConfig(float timeoutInSec, int retryTimes)
{
var timeout = TimeSpan.FromSeconds(timeoutInSec);
var handler = new System.Net.Http.HttpClientHandler(){
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
};
using (var httpClient = new System.Net.Http.HttpClient(handler))
{
httpClient.Timeout = timeout;
var stopwatch = new System.Diagnostics.Stopwatch();
try
{
stopwatch.Start();
var respon = await httpClient.GetAsync($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}");
stopwatch.Stop();
if (respon.IsSuccessStatusCode)
{
string remoteConfigStr = await respon.Content.ReadAsStringAsync();
await Awaiters.NextFrame;
return Decrypt(remoteConfigStr);
}
else
{
var elapsed = stopwatch.ElapsedMilliseconds;
Debug.LogWarning($"Load remote config failed {respon.StatusCode.ToString()}");
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", elapsed);
e.AddContent("reason", respon.StatusCode.ToString());
e.AddContent("skip", retryTimes >= 2);
e.AddContent("error", "http_request_failed");
}
#endif//AGG
}
}
catch (System.Net.Http.HttpRequestException httpEx)
{
if (stopwatch.IsRunning)
stopwatch.Stop();
var elapsed = stopwatch.Elapsed;
var errorMessage = $"HTTP request failed: {httpEx.Message}";
if (httpEx.InnerException != null)
{
errorMessage += $" Inner: {httpEx.InnerException.Message}";
if(httpEx.InnerException.InnerException != null)
{
errorMessage += $" InnerInner: {httpEx.InnerException.InnerException.Message}";
}
}
Debug.LogWarning(errorMessage);
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
e.AddContent("reason", "httpEx");
e.AddContent("skip", retryTimes >= 2);
e.AddContent("error", errorMessage);
}
#endif//AGG
}
catch (System.Threading.Tasks.TaskCanceledException timeoutEx)
{
if (stopwatch.IsRunning)
stopwatch.Stop();
var elapsed = stopwatch.Elapsed;
Debug.LogWarning($"Request timeout after {timeoutInSec}s: {timeoutEx.Message}");
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
e.AddContent("reason", $"timeout");
e.AddContent("skip", retryTimes >= 2);
e.AddContent("error", timeoutEx.Message);
}
#endif//AGG
}
catch (System.Security.Cryptography.CryptographicException cryptoEx)
{
if (stopwatch.IsRunning)
stopwatch.Stop();
var elapsed = stopwatch.Elapsed;
Debug.LogError($"Decryption failed: {cryptoEx.Message}");
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
e.AddContent("reason", "cryptoEx");
e.AddContent("skip", retryTimes >= 2);
e.AddContent("error", cryptoEx.Message);
}
#endif//AGG
}
catch (Exception exception)
{
if (stopwatch.IsRunning)
stopwatch.Stop();
var elapsed = stopwatch.ElapsedMilliseconds;
var errorMessage = $"Unexpected error loading remote config: {exception.Message}";
if (exception.InnerException != null)
{
errorMessage += $" Inner: {exception.InnerException.Message}";
}
Debug.LogError(errorMessage);
#if AGG
using (var e = GEvent.TackEvent("retry"))
{
e.AddContent("type", "config");
e.AddContent("duration_ms", elapsed);
e.AddContent("reason", "unexpected_error");
e.AddContent("skip", retryTimes >= 2);
e.AddContent("error", errorMessage);
}
#endif//AGG
}
}
return null;
}
*/
/*
* public static async Task<JSONNode> GetRemoteConfig()
* {
* UnityEngine.Assertions.Assert.IsNotNull(RemoteConfigUrl, "Config is not inited");
* var request = UnityWebRequest.Get($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}");
* request.timeout = 5;
* await request.SendWebRequest();
*
* if (request.result != UnityWebRequest.Result.Success)
* {
* return null;
* }
*
* string remoteConfigStr = request.downloadHandler.text;
* remoteConfigStr = Decrypt(remoteConfigStr);
* return SimpleJSON.JSON.Parse(remoteConfigStr);
* }
*/
const string RTMKey = "tbambooz";
private static string Decrypt(string text)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Key = Encoding.ASCII.GetBytes(RTMKey);
des.IV = Encoding.ASCII.GetBytes(RTMKey);
ICryptoTransform decryptor = des.CreateDecryptor(des.Key, des.IV);
byte[] inputBytes = Convert.FromBase64String(text);
byte[] outputBytes = decryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
return Encoding.UTF8.GetString(outputBytes);
}
private static JSONNode GetStreamingAssetConfig()
{
var debugConfigPath = GConstant.V_Debug_Config_Path;
var text = BetterStreamingAssets.ReadAllText(debugConfigPath);
//如果第一个字符是#e就返回false
if (!text.StartsWith("#"))
{
var debugConfig = SimpleJSON.JSON.Parse(text);
if (debugConfig.HasKey(GConstant.K_Static_Res_URL))
{
RemoteConfigUrl = debugConfig[GConstant.K_Static_Res_URL];
Debug.Log($"<color=yellow>Debug Static Res URL => {RemoteConfigUrl}</color>");
}
return debugConfig;
}
return null;
}
private static JSONNode GetPersistConfig()
{
var debugConfigPath = Path.Combine(Application.persistentDataPath, GConstant.V_Debug_Config_Path);
if (File.Exists(debugConfigPath))
{
var debugConfig = SimpleJSON.JSON.Parse(File.ReadAllText(debugConfigPath));
if (debugConfig.HasKey(GConstant.K_Static_Res_URL))
{
RemoteConfigUrl = debugConfig[GConstant.K_Static_Res_URL];
Debug.Log($"<color=yellow>Debug Static Res URL => {RemoteConfigUrl}</color>");
}
return debugConfig;
}
return null;
}
}