using System; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Networking; namespace tysdk { public interface IPaymentVerifier { Task Verify(PaymentInfo info); void Consume(string token); } public class VerifyResult { public bool success; public string msg; } public static class PaymentVerifierFactory { public static IPaymentVerifier GetVerifier() { return ChannelConfig.Channel switch { "Flexion" => new RetryablePaymentVerifier(new FlexionPaymentVerifier()), "Dummy" => new RetryablePaymentVerifier(new DummyPaymentVerifier()), _ => null }; } } public class RetryablePaymentVerifier : IPaymentVerifier { private readonly IPaymentVerifier _inner; private const int MaxRetries = 2; private static readonly TimeSpan RetryInterval = TimeSpan.FromSeconds(2); public RetryablePaymentVerifier(IPaymentVerifier inner) { _inner = inner; } public async Task Verify(PaymentInfo info) { VerifyResult lastResult = null; for (int attempt = 0; attempt <= MaxRetries; attempt++) { if (attempt > 0) { Debug.Log($"[RetryableVerifier] Flow retry {attempt}/{MaxRetries}, waiting {RetryInterval.TotalSeconds}s"); await Task.Delay(RetryInterval); } lastResult = await _inner.Verify(info); if (lastResult.success) return lastResult; Debug.LogWarning($"[RetryableVerifier] Flow attempt {attempt + 1} failed: {lastResult.msg}"); } return lastResult; } public void Consume(string token) => _inner.Consume(token); } public class FlexionPaymentVerifier : IPaymentVerifier { // TODO: 替换为实际游戏服务端验签 URL private const string VERIFY_URL = "https://YOUR_GAME_SERVER/api/pay/verify"; private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30); private const int MaxRetries = 2; private static readonly TimeSpan RetryBackoff = TimeSpan.FromSeconds(2); #if UNITY_EDITOR public async Task Verify(PaymentInfo info) { Debug.LogWarning("[FlexionPaymentVerifier] Editor placeholder: auto success"); await Task.Yield(); return new VerifyResult { success = true, msg = "editor_placeholder" }; } #else public async Task Verify(PaymentInfo info) { VerifyResult lastResult = null; for (int attempt = 0; attempt <= MaxRetries; attempt++) { if (attempt > 0) { var delay = TimeSpan.FromSeconds(RetryBackoff.TotalSeconds * attempt); Debug.Log($"[FlexionPaymentVerifier] HTTP retry {attempt}/{MaxRetries}, waiting {delay.TotalSeconds}s"); await Task.Delay(delay); } lastResult = await SendVerifyRequest(info); if (lastResult.success) return lastResult; Debug.LogWarning($"[FlexionPaymentVerifier] HTTP attempt {attempt + 1} failed: {lastResult.msg}"); } return lastResult; } private async Task SendVerifyRequest(PaymentInfo info) { var cts = new CancellationTokenSource(Timeout); try { Debug.Log("[FlexionPaymentVerifier] Sending verification request"); var body = JsonConvert.SerializeObject(info); using var req = new UnityWebRequest(VERIFY_URL, "POST"); req.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(body)); req.downloadHandler = new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json"); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); cts.Token.Register(() => tcs.TrySetResult(new VerifyResult { success = false, msg = "timeout" })); req.SendWebRequest().completed += _ => { if (req.result == UnityWebRequest.Result.Success) { Debug.Log("[FlexionPaymentVerifier] Response: " + req.downloadHandler.text); // TODO: 按实际服务端响应格式解析 tcs.TrySetResult(new VerifyResult { success = true, msg = "ok" }); } else { Debug.LogWarning("[FlexionPaymentVerifier] Failed: " + req.error); tcs.TrySetResult(new VerifyResult { success = false, msg = req.error }); } }; return await tcs.Task; } catch (Exception e) { Debug.LogError("[FlexionPaymentVerifier] Exception: " + e.Message); return new VerifyResult { success = false, msg = e.Message }; } finally { cts.Dispose(); } } #endif #if UNITY_EDITOR public void Consume(string token) { } #elif UNITY_ANDROID public void Consume(string token) { if (string.IsNullOrEmpty(token)) return; UnityBridgeFunc.ConsumePurchase(token); } #endif } public class DummyPaymentVerifier : IPaymentVerifier { public async Task Verify(PaymentInfo info) { Debug.Log("[DummyPaymentVerifier] Verifying purchase: " + info.orderId); await Task.Delay(500); return new VerifyResult { success = true, msg = "dummy_ok" }; } public void Consume(string token) { Debug.Log("[DummyPaymentVerifier] Consume: " + token); } } }