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 数据类型
/// 新的超时时间;若需立即按超时处理可使用
/// 找到未完成 pending 并成功重置则为 true
public bool ResetCallbackTimeout(TimeSpan newTimeout) where T : class
{
if (_disposed)
throw new ObjectDisposedException(nameof(TYSDKCallbackManager));
var callbackId = typeof(T).Name;
if (!_callbacks.TryGetValue(callbackId, out var entry))
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {callbackId}");
return false;
}
if (entry.Task.IsCompleted)
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] Callback {callbackId} already completed, cannot reset timeout");
return false;
}
var cts = entry.CancellationTokenSource;
if (cts == null)
return false;
try
{
cts.CancelAfter(newTimeout);
UnityEngine.Debug.Log($"[TYSDKCallbackManager] Reset timeout for {callbackId} to {newTimeout.TotalSeconds}s");
return true;
}
catch (ObjectDisposedException)
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] CancellationTokenSource already disposed for {callbackId}");
return false;
}
}
///
/// 触发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();
}
}
}
}