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 ); } } }