300 lines
12 KiB
C#
300 lines
12 KiB
C#
using System;
|
||
using System.Threading.Tasks;
|
||
using Logic.CrashSight;
|
||
using MemoryPack;
|
||
using RuntimeData;
|
||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||
using Steamworks;
|
||
#endif
|
||
using TH1_Logic.Collect;
|
||
using TH1_Logic.Config;
|
||
using TH1_Logic.Core;
|
||
using TH1_Logic.GameArchive;
|
||
using TH1_Logic.Net;
|
||
using TH1_Logic.Tools;
|
||
using UnityEngine;
|
||
|
||
namespace TH1_Logic.Oss
|
||
{
|
||
public class OssManager
|
||
{
|
||
public static OssManager Instance = new OssManager();
|
||
private const string FunctionUrl = "https://get-sts-token-qltjykaafr.cn-shanghai.fcapp.run";
|
||
|
||
private readonly StsTokenService _stsService;
|
||
private readonly OssUploadService _uploadService;
|
||
|
||
private StsCredentials _cachedCredentials;
|
||
private DateTime _credentialsExpireTime;
|
||
|
||
private StsCredentials _cachedCollectCredentials;
|
||
private DateTime _collectCredentialsExpireTime;
|
||
|
||
public const int MaxBugReportUploadBytes = PlayerBugReportService.MaxBugReportUploadBytes;
|
||
public const int MaxMultilingualReportUploadBytes = PlayerMultilingualReportService.MaxMultilingualReportUploadBytes;
|
||
private const int SteamAuthWarmupRetrySeconds = 30;
|
||
private const int SteamAuthWarmupRefreshSeconds = 4 * 60;
|
||
|
||
private DateTime _nextSteamAuthWarmupTime = DateTime.MinValue;
|
||
private bool _isSteamAuthWarmupRunning;
|
||
|
||
public OssManager()
|
||
{
|
||
_stsService = new StsTokenService(FunctionUrl);
|
||
_uploadService = new OssUploadService();
|
||
}
|
||
|
||
public void UploadMapData(string steamId, MapData endMap)
|
||
{
|
||
if (endMap.Net.Mode == NetMode.Multi && !LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (!GameArchiveManager.Instance.TryLoadCurrentBeginArchive(endMap.Net.Mode, out var beginMap))
|
||
{
|
||
LogSystem.LogError($"UploadMapData Error beginMap is null : {endMap.Net.Mode} {endMap.MapID}");
|
||
return;
|
||
}
|
||
|
||
var ossData = new OssData();
|
||
ossData.StartMap = beginMap;
|
||
ossData.Actions = endMap.Net.Actions;
|
||
ossData.CollectData = CollectManager.Instance.CollectData;
|
||
ossData.CollectData.MemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
|
||
byte[] bytes = TH1Serialization.Serialize(ossData);
|
||
_ = UploadGameDataAsync(steamId, bytes);
|
||
}
|
||
|
||
public async Task<bool> UploadGameDataAsync(string steamId, byte[] data)
|
||
{
|
||
try
|
||
{
|
||
// 检查缓存的凭证是否有效(提前60秒刷新)
|
||
if (_cachedCredentials == null || DateTime.UtcNow >= _credentialsExpireTime.AddSeconds(-60))
|
||
{
|
||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||
_cachedCredentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "ossdata");
|
||
_credentialsExpireTime = DateTime.UtcNow.AddSeconds(_cachedCredentials.expiresIn);
|
||
LogSystem.LogInfo($"STS token obtained, expires at {_credentialsExpireTime}");
|
||
}
|
||
|
||
var result = await _uploadService.UploadFileAsync(_cachedCredentials, data);
|
||
if (result)
|
||
{
|
||
LogSystem.LogInfo($"Upload success: {_cachedCredentials.objectKey}");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogSystem.LogError($"Upload failed: {ex.Message}");
|
||
_cachedCredentials = null;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void UploadCollectData(string steamId, MapData endMap)
|
||
{
|
||
if (endMap.Net.Mode == NetMode.Multi && !LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
var collectData = CollectManager.Instance.CollectData;
|
||
collectData.MemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
|
||
collectData.Version = ConfigManager.Instance.VersionCfg.CurVersionInfo.Version;
|
||
_ = UploadCollectDataAsync(steamId, collectData);
|
||
}
|
||
|
||
public async Task<bool> UploadCollectDataAsync(string steamId, CollectData collectData)
|
||
{
|
||
try
|
||
{
|
||
// 检查缓存的凭证是否有效(提前60秒刷新)
|
||
if (_cachedCollectCredentials == null || DateTime.UtcNow >= _collectCredentialsExpireTime.AddSeconds(-60))
|
||
{
|
||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||
_cachedCollectCredentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "collectdata");
|
||
_collectCredentialsExpireTime = DateTime.UtcNow.AddSeconds(_cachedCollectCredentials.expiresIn);
|
||
LogSystem.LogInfo($"Collect STS token obtained, expires at {_collectCredentialsExpireTime}");
|
||
}
|
||
|
||
byte[] data = TH1Serialization.Serialize(collectData);
|
||
var result = await _uploadService.UploadFileAsync(_cachedCollectCredentials, data);
|
||
if (result)
|
||
{
|
||
LogSystem.LogInfo($"CollectData upload success: {_cachedCollectCredentials.objectKey}");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogSystem.LogError($"CollectData upload failed: {ex.Message}");
|
||
_cachedCollectCredentials = null;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public async Task<(bool success, string objectKey)> UploadPlayerBugReportAsync(string steamId, byte[] packageData,
|
||
string version)
|
||
{
|
||
try
|
||
{
|
||
if (packageData == null || packageData.Length == 0)
|
||
{
|
||
LogSystem.LogError("PlayerBugReport upload failed: package data is empty");
|
||
return (false, null);
|
||
}
|
||
|
||
if (packageData.Length > MaxBugReportUploadBytes)
|
||
{
|
||
LogSystem.LogError($"PlayerBugReport upload failed: package size {packageData.Length} exceeds {MaxBugReportUploadBytes}");
|
||
return (false, null);
|
||
}
|
||
|
||
if (!TryGetAuthTicket(out var authTicket)) return (false, null);
|
||
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "bugreport", version);
|
||
var result = await _uploadService.UploadFileAsync(credentials, packageData, "application/zip",
|
||
MaxBugReportUploadBytes);
|
||
if (result)
|
||
{
|
||
LogSystem.LogInfo($"PlayerBugReport upload success: {credentials.objectKey}");
|
||
return (true, credentials.objectKey);
|
||
}
|
||
|
||
return (false, credentials.objectKey);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogSystem.LogError($"PlayerBugReport upload failed: {ex.Message}");
|
||
return (false, null);
|
||
}
|
||
}
|
||
|
||
public async Task<(bool success, string objectKey)> UploadPlayerMultilingualReportAsync(string steamId,
|
||
byte[] packageData, string version)
|
||
{
|
||
try
|
||
{
|
||
if (packageData == null || packageData.Length == 0)
|
||
{
|
||
LogSystem.LogError("PlayerMultilingualReport upload failed: package data is empty");
|
||
return (false, null);
|
||
}
|
||
|
||
if (packageData.Length > MaxMultilingualReportUploadBytes)
|
||
{
|
||
LogSystem.LogError(
|
||
$"PlayerMultilingualReport upload failed: package size {packageData.Length} exceeds {MaxMultilingualReportUploadBytes}");
|
||
return (false, null);
|
||
}
|
||
|
||
if (!TryGetAuthTicket(out var authTicket)) return (false, null);
|
||
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "multilingualreport",
|
||
version);
|
||
var result = await _uploadService.UploadFileAsync(credentials, packageData, "application/zip",
|
||
MaxMultilingualReportUploadBytes);
|
||
if (result)
|
||
{
|
||
LogSystem.LogInfo($"PlayerMultilingualReport upload success: {credentials.objectKey}");
|
||
return (true, credentials.objectKey);
|
||
}
|
||
|
||
return (false, credentials.objectKey);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogSystem.LogError($"PlayerMultilingualReport upload failed: {ex.Message}");
|
||
return (false, null);
|
||
}
|
||
}
|
||
|
||
public void UpdateSteamAuthWarmup()
|
||
{
|
||
if (Logic.AI.AIDirectorBatchRuntime.SkipPresentationWait) return;
|
||
if (_isSteamAuthWarmupRunning) return;
|
||
if (DateTime.UtcNow < _nextSteamAuthWarmupTime) return;
|
||
|
||
if (!TryGetSteamId(out var steamId))
|
||
{
|
||
_nextSteamAuthWarmupTime = DateTime.UtcNow.AddSeconds(15);
|
||
return;
|
||
}
|
||
|
||
_ = WarmupSteamAuthAsync(steamId);
|
||
}
|
||
|
||
public async Task<bool> WarmupSteamAuthAsync(string steamId)
|
||
{
|
||
_isSteamAuthWarmupRunning = true;
|
||
try
|
||
{
|
||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||
var response = await _stsService.WarmupSteamAuthAsync(steamId, authTicket);
|
||
var refreshSeconds = response != null && response.expiresIn > 90
|
||
? Math.Min(SteamAuthWarmupRefreshSeconds, response.expiresIn - 60)
|
||
: SteamAuthWarmupRetrySeconds;
|
||
_nextSteamAuthWarmupTime = DateTime.UtcNow.AddSeconds(refreshSeconds);
|
||
LogSystem.LogInfo($"Steam auth warmup success, cached={response?.cached}, expiresIn={response?.expiresIn}s");
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_nextSteamAuthWarmupTime = DateTime.UtcNow.AddSeconds(SteamAuthWarmupRetrySeconds);
|
||
LogSystem.LogWarning($"Steam auth warmup failed: {ex.Message}");
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
_isSteamAuthWarmupRunning = false;
|
||
}
|
||
}
|
||
|
||
private static bool TryGetSteamId(out string steamId)
|
||
{
|
||
steamId = "";
|
||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||
try
|
||
{
|
||
if (!SteamUser.BLoggedOn()) return false;
|
||
|
||
var id = SteamUser.GetSteamID().m_SteamID;
|
||
if (id == 0) return false;
|
||
|
||
steamId = id.ToString();
|
||
return true;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
|
||
private static bool TryGetAuthTicket(out string authTicket)
|
||
{
|
||
authTicket = null;
|
||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||
try
|
||
{
|
||
var ticket = new byte[1024];
|
||
var identity = new SteamNetworkingIdentity();
|
||
SteamUser.GetAuthSessionTicket(ticket, 1024, out var ticketSize, ref identity);
|
||
if (ticketSize == 0)
|
||
{
|
||
LogSystem.LogWarning("Steam auth ticket is empty");
|
||
return false;
|
||
}
|
||
|
||
authTicket = BitConverter.ToString(ticket, 0, (int)ticketSize).Replace("-", "").ToLower();
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogSystem.LogWarning($"Steam auth ticket unavailable: {ex.Message}");
|
||
return false;
|
||
}
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
}
|
||
}
|