using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace tysdk { /// /// 线程安全的异步Callback管理器 /// 解决原有callback系统的线程安全、内存泄漏和超时问题 /// public class TYSDKCallbackManager : IDisposable { private static readonly Lazy _instance = new Lazy(() => new TYSDKCallbackManager()); public static TYSDKCallbackManager Instance => _instance.Value; private readonly ConcurrentDictionary _callbacks = new(); private readonly object _lock = new(); private bool _disposed = false; private TYSDKCallbackManager() { } /// /// 注册一个callback并返回Task /// /// Callback数据类型 /// Callback类型标识 /// 超时时间,默认15 sec /// Task用于等待callback结果 public Task RegisterCallback(TimeSpan? timeout = null) where T : class { if (_disposed) throw new ObjectDisposedException(nameof(TYSDKCallbackManager)); var callbackId = typeof(T).Name; if (_callbacks.TryGetValue(callbackId, out var entry)) { UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback exists {callbackId}"); return entry.Task as Task; } var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var actualTimeout = timeout ?? TimeSpan.FromSeconds(15); var cts = new CancellationTokenSource(actualTimeout); entry = new CallbackEntry { TaskCompletionSource = tcs, CancellationTokenSource = cts, }; // 注册到字典 _callbacks[callbackId] = entry; // 设置超时取消 cts.Token.Register(() => { if (tcs.TrySetCanceled()) { UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] Callback {callbackId} timed out after {actualTimeout.TotalSeconds}s"); } _callbacks.TryRemove(callbackId, out _); }); UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback {callbackId}"); return tcs.Task; } /// /// 触发callback /// /// Callback数据类型 /// Callback类型标识 /// Callback数据 /// 是否成功触发callback public bool TryTriggerCallback(T callbackData) where T : class { if (_disposed || callbackData == null) return false; var key = typeof(T).Name; if (!_callbacks.TryGetValue(key, out var entry)) { UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}"); return false; } if (entry == null) { _callbacks.TryRemove(key, out _); return false; } if (entry.Task.IsCompleted) { entry.CancellationTokenSource?.Cancel(); _callbacks.TryRemove(key, out _); return false; } var actualEntry = entry as CallbackEntry; if (actualEntry == null) { UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Callback type mismatch: Expected {typeof(T).Name}, but got {entry.GetType().Name}"); entry.CancellationTokenSource?.Cancel(); return false; } try { // 尝试设置结果 if (actualEntry.TaskCompletionSource.TrySetResult(callbackData)) { actualEntry.CancellationTokenSource?.Cancel(); UnityEngine.Debug.Log($"[TYSDKCallbackManager] Successfully triggered callback {key}"); return true; } } catch (Exception ex) { UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Error triggering callback {key}: {ex.Message}\n{ex.StackTrace}"); actualEntry.TaskCompletionSource.TrySetException(ex); actualEntry.CancellationTokenSource?.Cancel(); return false; } return false; } /// /// 取消指定类型的所有callback /// /// Callback类型 /// 取消原因 public void CancelCallbacks() { var key = typeof(T).Name; if (!_callbacks.TryGetValue(key, out var entryToRemove)) { UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}"); return; } entryToRemove.Cancel(); } public int GetCallbackNum() { return _callbacks?.Count ?? 0; } public void Dispose() { if (_disposed) return; lock (_lock) { if (_disposed) return; _disposed = true; // 取消所有pending callbacks foreach (var entry in _callbacks.Values) { try { if (!entry.Task.IsCompleted) { entry.Cancel(); } } catch { // 忽略取消时的异常 } entry.CancellationTokenSource?.Dispose(); } _callbacks.Clear(); UnityEngine.Debug.Log("[TYSDKCallbackManager] Disposed"); } } private abstract class CallbackEntry { public CancellationTokenSource CancellationTokenSource { get; set; } = null!; public abstract Task Task { get; } public abstract void Cancel(); } private class CallbackEntry : CallbackEntry where T : class { public TaskCompletionSource TaskCompletionSource { get; set; } = null!; public override Task Task => TaskCompletionSource.Task; public override void Cancel() { TaskCompletionSource.TrySetCanceled(); CancellationTokenSource?.Cancel(); } } } }