using System;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace AIImages.Helpers
{
///
/// Вспомогательный класс для правильной обработки асинхронных операций в RimWorld
/// Предотвращает fire-and-forget паттерн и обеспечивает централизованную обработку ошибок
///
public static class AsyncHelper
{
///
/// Выполняет асинхронную задачу с обработкой ошибок
///
public static async Task RunAsync(Func taskFunc, string operationName = "Operation")
{
try
{
await taskFunc();
}
catch (OperationCanceledException)
{
Log.Message($"[AI Images] {operationName} was cancelled");
Messages.Message($"{operationName} was cancelled", MessageTypeDefOf.RejectInput);
}
catch (Exception ex)
{
Log.Error($"[AI Images] Error in {operationName}: {ex.Message}\n{ex.StackTrace}");
Messages.Message(
$"Error in {operationName}: {ex.Message}",
MessageTypeDefOf.RejectInput
);
}
}
///
/// Выполняет асинхронную задачу с обработкой ошибок и callback при успехе
///
public static async Task RunAsync(
Func> taskFunc,
Action onSuccess,
string operationName = "Operation"
)
{
try
{
T result = await taskFunc();
onSuccess?.Invoke(result);
}
catch (OperationCanceledException)
{
Log.Message($"[AI Images] {operationName} was cancelled");
Messages.Message($"{operationName} was cancelled", MessageTypeDefOf.RejectInput);
}
catch (Exception ex)
{
Log.Error($"[AI Images] Error in {operationName}: {ex.Message}\n{ex.StackTrace}");
Messages.Message(
$"Error in {operationName}: {ex.Message}",
MessageTypeDefOf.RejectInput
);
}
}
///
/// Выполняет асинхронную задачу с полным контролем: onSuccess, onError, onCancel
///
public static async Task RunAsync(
Func> taskFunc,
Action onSuccess,
Action onError = null,
Action onCancel = null,
string operationName = "Operation"
)
{
try
{
T result = await taskFunc();
onSuccess?.Invoke(result);
}
catch (OperationCanceledException)
{
Log.Message($"[AI Images] {operationName} was cancelled");
if (onCancel != null)
{
onCancel();
}
else
{
Messages.Message(
$"{operationName} was cancelled",
MessageTypeDefOf.RejectInput
);
}
}
catch (Exception ex)
{
Log.Error($"[AI Images] Error in {operationName}: {ex.Message}\n{ex.StackTrace}");
if (onError != null)
{
onError(ex);
}
else
{
Messages.Message(
$"Error in {operationName}: {ex.Message}",
MessageTypeDefOf.RejectInput
);
}
}
}
///
/// Безопасно выполняет Task без ожидания результата, с логированием ошибок
/// Используется когда нужен fire-and-forget, но с обработкой ошибок
///
public static void FireAndForget(Task task, string operationName = "Background operation")
{
if (task == null)
return;
task.ContinueWith(
t =>
{
if (t.IsFaulted && t.Exception != null)
{
var ex = t.Exception.GetBaseException();
Log.Error(
$"[AI Images] Error in {operationName}: {ex.Message}\n{ex.StackTrace}"
);
}
else if (t.IsCanceled)
{
Log.Message($"[AI Images] {operationName} was cancelled");
}
},
TaskScheduler.Default
);
}
}
}