Guest User

Untitled

a guest
Aug 16th, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 40.95 KB | None | 0 0
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using NECS.Core.Logging;
  8. using NECS.ECS.ECSCore;
  9. using NECS.Extensions;
  10. using NECS.Extensions.ThreadingSync;
  11. using NECS.GameEngineAPI;
  12.  
  13. namespace NECS.Harness.Model
  14. {
  15.     public abstract
  16. #if GODOT4_0_OR_GREATER
  17.     partial
  18. #endif
  19.     class IService : SGT
  20.     {
  21.         #region SyncManagers
  22.        
  23.         // Информация о callback-е
  24.         public class ServiceCallback
  25.         {
  26.             public string ServiceId { get; set; }
  27.             public string AuthorServiceId { get; set; } // Сервис, который создал этот callback
  28.             public int TargetStep { get; set; }
  29.             public int AuthorBlockingStep { get; set; } // Шаг, с которого начинать блокировать автора
  30.             public Func<Dictionary<string, ServiceStepInfo>, bool> Condition { get; set; }
  31.             public Action Callback { get; set; }
  32.             public bool IsCompleted { get; set; }
  33.             public bool IsRunning { get; set; }
  34.            
  35.             public ServiceCallback(string serviceId, string authorServiceId, int targetStep, int authorBlockingStep, Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
  36.             {
  37.                 ServiceId = serviceId;
  38.                 AuthorServiceId = authorServiceId;
  39.                 TargetStep = targetStep;
  40.                 AuthorBlockingStep = authorBlockingStep;
  41.                 Condition = condition;
  42.                 Callback = callback;
  43.                 IsCompleted = false;
  44.                 IsRunning = false;
  45.             }
  46.         }
  47.  
  48.         // Информация о состоянии шага сервиса
  49.         public class ServiceStepInfo
  50.         {
  51.             public string ServiceId { get; set; }
  52.             public int CurrentStep { get; set; }
  53.             public int TotalSteps { get; set; }
  54.             public bool IsStepCompleted { get; set; }
  55.             public bool IsServiceFailed { get; set; }
  56.             public bool IsStepRunning { get; set; }
  57.             public bool IsFrozen { get; set; } // Новое поле для отслеживания заморозки
  58.             public DateTime StepStartTime { get; set; }
  59.             public DateTime? StepEndTime { get; set; }
  60.             public DateTime? FrozenTime { get; set; } // Время заморозки
  61.            
  62.             public ServiceStepInfo(string serviceId, int totalSteps)
  63.             {
  64.                 ServiceId = serviceId;
  65.                 CurrentStep = 0;
  66.                 TotalSteps = totalSteps;
  67.                 IsStepCompleted = false;
  68.                 IsServiceFailed = false;
  69.                 IsStepRunning = false;
  70.                 IsFrozen = false;
  71.                 StepStartTime = DateTime.Now;
  72.             }
  73.            
  74.             public ServiceStepInfo Clone()
  75.             {
  76.                 return new ServiceStepInfo(ServiceId, TotalSteps)
  77.                 {
  78.                     CurrentStep = this.CurrentStep,
  79.                     IsStepCompleted = this.IsStepCompleted,
  80.                     IsServiceFailed = this.IsServiceFailed,
  81.                     IsStepRunning = this.IsStepRunning,
  82.                     IsFrozen = this.IsFrozen,
  83.                     StepStartTime = this.StepStartTime,
  84.                     StepEndTime = this.StepEndTime,
  85.                     FrozenTime = this.FrozenTime
  86.                 };
  87.             }
  88.         }
  89.  
  90.         // Event Loop события
  91.         public abstract class EventLoopEvent
  92.         {
  93.             public DateTime Timestamp { get; private set; }
  94.            
  95.             protected EventLoopEvent()
  96.             {
  97.                 Timestamp = DateTime.Now;
  98.             }
  99.         }
  100.  
  101.         public class RegisterServiceEvent : EventLoopEvent
  102.         {
  103.             public string ServiceId { get; set; }
  104.             public Action<int>[] Steps { get; set; }
  105.            
  106.             public RegisterServiceEvent(string serviceId, Action<int>[] steps)
  107.             {
  108.                 ServiceId = serviceId;
  109.                 Steps = steps;
  110.             }
  111.         }
  112.  
  113.         public class RegisterCallbackEvent : EventLoopEvent
  114.         {
  115.             public string TargetServiceId { get; set; }
  116.             public string AuthorServiceId { get; set; }
  117.             public int TargetStep { get; set; }
  118.             public int AuthorBlockingStep { get; set; }
  119.             public Func<Dictionary<string, ServiceStepInfo>, bool> Condition { get; set; }
  120.             public Action Callback { get; set; }
  121.            
  122.             public RegisterCallbackEvent(string targetServiceId, string authorServiceId, int targetStep, int authorBlockingStep,
  123.                 Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
  124.             {
  125.                 TargetServiceId = targetServiceId;
  126.                 AuthorServiceId = authorServiceId;
  127.                 TargetStep = targetStep;
  128.                 AuthorBlockingStep = authorBlockingStep;
  129.                 Condition = condition;
  130.                 Callback = callback;
  131.             }
  132.         }
  133.  
  134.         public class CompleteStepEvent : EventLoopEvent
  135.         {
  136.             public string ServiceId { get; set; }
  137.            
  138.             public CompleteStepEvent(string serviceId)
  139.             {
  140.                 ServiceId = serviceId;
  141.             }
  142.         }
  143.  
  144.         public class FailServiceEvent : EventLoopEvent
  145.         {
  146.             public string ServiceId { get; set; }
  147.             public string Reason { get; set; }
  148.            
  149.             public FailServiceEvent(string serviceId, string reason)
  150.             {
  151.                 ServiceId = serviceId;
  152.                 Reason = reason;
  153.             }
  154.         }
  155.  
  156.         public class CallbackCompletedEvent : EventLoopEvent
  157.         {
  158.             public ServiceCallback Callback { get; set; }
  159.             public bool Success { get; set; }
  160.             public string ErrorMessage { get; set; }
  161.            
  162.             public CallbackCompletedEvent(ServiceCallback callback, bool success, string errorMessage = null)
  163.             {
  164.                 Callback = callback;
  165.                 Success = success;
  166.                 ErrorMessage = errorMessage;
  167.             }
  168.         }
  169.  
  170.         // Новые события для заморозки/разморозки
  171.         public class FreezeServiceEvent : EventLoopEvent
  172.         {
  173.             public string ServiceId { get; set; }
  174.            
  175.             public FreezeServiceEvent(string serviceId)
  176.             {
  177.                 ServiceId = serviceId;
  178.             }
  179.         }
  180.  
  181.         public class UnfreezeServiceEvent : EventLoopEvent
  182.         {
  183.             public string ServiceId { get; set; }
  184.            
  185.             public UnfreezeServiceEvent(string serviceId)
  186.             {
  187.                 ServiceId = serviceId;
  188.             }
  189.         }
  190.  
  191.         // Система синхронизации с Event Loop
  192.         public class ServiceSynchronizationManager
  193.         {
  194.             // Event Loop - потокобезопасная очередь событий
  195.             private readonly ConcurrentQueue<EventLoopEvent> _eventQueue = new ConcurrentQueue<EventLoopEvent>();
  196.            
  197.             // Основное состояние (обрабатывается только в мониторинговом потоке)
  198.             private readonly Dictionary<string, ServiceStepInfo> _serviceStates = new Dictionary<string, ServiceStepInfo>();
  199.            
  200.             // ИСПРАВЛЕНИЕ: Callback'и теперь индексируются по комбинации serviceId + step
  201.             private readonly Dictionary<string, Dictionary<int, List<ServiceCallback>>> _serviceStepCallbacks = new Dictionary<string, Dictionary<int, List<ServiceCallback>>>();
  202.             private readonly Dictionary<string, Action<int>[]> _serviceSteps = new Dictionary<string, Action<int>[]>();
  203.            
  204.             // Отслеживание callback'ов по сервисам-авторам
  205.             private readonly Dictionary<string, List<ServiceCallback>> _authorCallbacks = new Dictionary<string, List<ServiceCallback>>();
  206.            
  207.             private bool _isMonitoringRunning = false;
  208.             private bool _stopMonitoring = false;
  209.             // УДАЛЯЕМ: _currentMonitoringStep больше не нужен
  210.            
  211.             // События (потокобезопасные)
  212.             public event Action<string, int, string> OnServiceStepChanged;
  213.             public event Action<string, string> OnServiceFailed;
  214.             public event Action<string> OnServiceCompleted;
  215.             public event Action OnAllServicesCompleted;
  216.             public event Action<string> OnServiceFrozen; // Новое событие
  217.             public event Action<string> OnServiceUnfrozen; // Новое событие
  218.            
  219.             // Асинхронная регистрация сервиса через Event Loop
  220.             public void RegisterService(string serviceId, Action<int>[] steps)
  221.             {
  222.                 _eventQueue.Enqueue(new RegisterServiceEvent(serviceId, steps));
  223.             }
  224.            
  225.             // Асинхронная регистрация callback-а через Event Loop
  226.             public void RegisterCallback(string targetServiceId, string authorServiceId, int targetStep, int authorBlockingStep,
  227.                 Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
  228.             {
  229.                 _eventQueue.Enqueue(new RegisterCallbackEvent(targetServiceId, authorServiceId, targetStep, authorBlockingStep, condition, callback));
  230.             }
  231.  
  232.             // Асинхронное завершение шага через Event Loop
  233.             public void CompleteCurrentStep(string serviceId)
  234.             {
  235.                 _eventQueue.Enqueue(new CompleteStepEvent(serviceId));
  236.             }
  237.            
  238.             // Асинхронная отметка об ошибке сервиса через Event Loop
  239.             public void FailService(string serviceId, string reason)
  240.             {
  241.                 _eventQueue.Enqueue(new FailServiceEvent(serviceId, reason));
  242.             }
  243.  
  244.             // Новые методы для заморозки/разморозки
  245.             public void FreezeServiceInitialization(string serviceId)
  246.             {
  247.                 _eventQueue.Enqueue(new FreezeServiceEvent(serviceId));
  248.             }
  249.  
  250.             public void UnfreezeServiceInitialization(string serviceId)
  251.             {
  252.                 _eventQueue.Enqueue(new UnfreezeServiceEvent(serviceId));
  253.             }
  254.            
  255.             // Асинхронное уведомление о завершении callback-а через Event Loop
  256.             internal void NotifyCallbackCompleted(ServiceCallback callback, bool success, string errorMessage = null)
  257.             {
  258.                 _eventQueue.Enqueue(new CallbackCompletedEvent(callback, success, errorMessage));
  259.             }
  260.  
  261.             // Запуск Event Loop мониторинга
  262.             public void StartAllServices(int awaitServicesCount = 0)
  263.             {
  264.                 bool shouldStart = false;
  265.                
  266.                 // Атомарная проверка и установка флага
  267.                 if (!_isMonitoringRunning)
  268.                 {
  269.                     _isMonitoringRunning = true;
  270.                     _stopMonitoring = false;
  271.                     shouldStart = true;
  272.                 }
  273.                
  274.                 if (shouldStart)
  275.                 {
  276.                     TaskEx.RunAsync(() => EventLoopMonitoring(awaitServicesCount));
  277.                 }
  278.             }
  279.            
  280.             // Остановка мониторинга
  281.             public void StopMonitoring()
  282.             {
  283.                 _stopMonitoring = true;
  284.             }
  285.            
  286.             // Основной Event Loop мониторинг (выполняется в одном потоке)
  287.             private void EventLoopMonitoring(int awaitServicesCount)
  288.             {
  289.                 while (!_stopMonitoring && (!AreAllServicesCompleted() || _serviceStates.Count < awaitServicesCount))
  290.                 {
  291.                     // Обрабатываем все события из очереди
  292.                     ProcessEventQueue();
  293.                    
  294.                     // Выполняем логику мониторинга
  295.                     ProcessMonitoringStep();
  296.                    
  297.                     // Небольшая задержка
  298.                     Thread.Sleep(10);
  299.                 }
  300.                
  301.                 // Обрабатываем оставшиеся события
  302.                 ProcessEventQueue();
  303.                
  304.                 _isMonitoringRunning = false;
  305.                
  306.                 if (AreAllServicesCompleted())
  307.                 {
  308.                     OnAllServicesCompleted?.Invoke();
  309.                 }
  310.             }
  311.            
  312.             // Обработка всех событий из очереди (синхронно в мониторинговом потоке)
  313.             private void ProcessEventQueue()
  314.             {
  315.                 while (_eventQueue.TryDequeue(out var eventItem))
  316.                 {
  317.                     ProcessEvent(eventItem);
  318.                 }
  319.             }
  320.            
  321.             // Обработка одного события (синхронно, без блокировок)
  322.             private void ProcessEvent(EventLoopEvent eventItem)
  323.             {
  324.                 switch (eventItem)
  325.                 {
  326.                     case RegisterServiceEvent registerEvent:
  327.                         ProcessRegisterService(registerEvent);
  328.                         break;
  329.                        
  330.                     case RegisterCallbackEvent callbackEvent:
  331.                         ProcessRegisterCallback(callbackEvent);
  332.                         break;
  333.                        
  334.                     case CompleteStepEvent completeEvent:
  335.                         ProcessCompleteStep(completeEvent);
  336.                         break;
  337.                        
  338.                     case FailServiceEvent failEvent:
  339.                         ProcessFailService(failEvent);
  340.                         break;
  341.                        
  342.                     case CallbackCompletedEvent callbackCompletedEvent:
  343.                         ProcessCallbackCompleted(callbackCompletedEvent);
  344.                         break;
  345.                        
  346.                     case FreezeServiceEvent freezeEvent:
  347.                         ProcessFreezeService(freezeEvent);
  348.                         break;
  349.                        
  350.                     case UnfreezeServiceEvent unfreezeEvent:
  351.                         ProcessUnfreezeService(unfreezeEvent);
  352.                         break;
  353.                 }
  354.             }
  355.            
  356.             // Обработка регистрации сервиса (синхронно)
  357.             private void ProcessRegisterService(RegisterServiceEvent eventItem)
  358.             {
  359.                 _serviceSteps[eventItem.ServiceId] = eventItem.Steps;
  360.                 _serviceStates[eventItem.ServiceId] = new ServiceStepInfo(eventItem.ServiceId, eventItem.Steps.Length);
  361.                
  362.                 // ИСПРАВЛЕНИЕ: Инициализируем структуру callback'ов для каждого сервиса
  363.                 if (!_serviceStepCallbacks.ContainsKey(eventItem.ServiceId))
  364.                 {
  365.                     _serviceStepCallbacks[eventItem.ServiceId] = new Dictionary<int, List<ServiceCallback>>();
  366.                 }
  367.                
  368.                 // Инициализируем список callback'ов для этого сервиса-автора
  369.                 if (!_authorCallbacks.ContainsKey(eventItem.ServiceId))
  370.                 {
  371.                     _authorCallbacks[eventItem.ServiceId] = new List<ServiceCallback>();
  372.                 }
  373.                
  374.                 IService.getInstance<IService>(eventItem.ServiceId).SetupCallbacks(IService.AllServiceList.ToList());
  375.                
  376.                 OnServiceStepChanged?.Invoke(eventItem.ServiceId, 0, "Service registered");
  377.             }
  378.            
  379.             // ИСПРАВЛЕНИЕ: Обработка регистрации callback-а (синхронно)
  380.             public void ProcessRegisterCallback(RegisterCallbackEvent eventItem)
  381.             {
  382.                 // Инициализируем структуру для целевого сервиса, если её нет
  383.                 if (!_serviceStepCallbacks.ContainsKey(eventItem.TargetServiceId))
  384.                 {
  385.                     _serviceStepCallbacks[eventItem.TargetServiceId] = new Dictionary<int, List<ServiceCallback>>();
  386.                 }
  387.                
  388.                 // Инициализируем список для конкретного шага целевого сервиса
  389.                 if (!_serviceStepCallbacks[eventItem.TargetServiceId].ContainsKey(eventItem.TargetStep))
  390.                 {
  391.                     _serviceStepCallbacks[eventItem.TargetServiceId][eventItem.TargetStep] = new List<ServiceCallback>();
  392.                 }
  393.                
  394.                 var callback = new ServiceCallback(
  395.                     eventItem.TargetServiceId,
  396.                     eventItem.AuthorServiceId,
  397.                     eventItem.TargetStep,
  398.                     eventItem.AuthorBlockingStep,
  399.                     eventItem.Condition,
  400.                     eventItem.Callback);
  401.                
  402.                 _serviceStepCallbacks[eventItem.TargetServiceId][eventItem.TargetStep].Add(callback);
  403.                
  404.                 // Добавляем callback в список callback'ов автора
  405.                 if (!_authorCallbacks.ContainsKey(eventItem.AuthorServiceId))
  406.                 {
  407.                     _authorCallbacks[eventItem.AuthorServiceId] = new List<ServiceCallback>();
  408.                 }
  409.                 _authorCallbacks[eventItem.AuthorServiceId].Add(callback);
  410.             }
  411.  
  412.             // Обработка завершения шага (синхронно)
  413.             private void ProcessCompleteStep(CompleteStepEvent eventItem)
  414.             {
  415.                 if (!_serviceStates.ContainsKey(eventItem.ServiceId))
  416.                     return;
  417.  
  418.                 var serviceState = _serviceStates[eventItem.ServiceId];
  419.                 if (serviceState.IsServiceFailed || serviceState.IsFrozen) // Проверяем заморозку
  420.                     return;
  421.  
  422.                 int currentStep = serviceState.CurrentStep;
  423.  
  424.                 OnServiceStepChanged?.Invoke(eventItem.ServiceId, currentStep, $"Step {currentStep} completed");
  425.  
  426.                 // Проверяем, завершен ли сервис
  427.                 if (currentStep >= serviceState.TotalSteps - 1)
  428.                 {
  429.                     OnServiceCompleted?.Invoke(eventItem.ServiceId);
  430.                 }
  431.                
  432.                 serviceState.IsStepCompleted = true;
  433.                 serviceState.IsStepRunning = false;
  434.                 serviceState.StepEndTime = DateTime.Now;
  435.             }
  436.            
  437.             // Обработка ошибки сервиса (синхронно)
  438.             private void ProcessFailService(FailServiceEvent eventItem)
  439.             {
  440.                 if (_serviceStates.ContainsKey(eventItem.ServiceId))
  441.                 {
  442.                     _serviceStates[eventItem.ServiceId].IsServiceFailed = true;
  443.                     _serviceStates[eventItem.ServiceId].IsStepRunning = false;
  444.                     OnServiceFailed?.Invoke(eventItem.ServiceId, eventItem.Reason);
  445.                 }
  446.             }
  447.  
  448.             // Обработка заморозки сервиса (синхронно)
  449.             private void ProcessFreezeService(FreezeServiceEvent eventItem)
  450.             {
  451.                 if (_serviceStates.ContainsKey(eventItem.ServiceId))
  452.                 {
  453.                     var serviceState = _serviceStates[eventItem.ServiceId];
  454.                     if (!serviceState.IsFrozen)
  455.                     {
  456.                         serviceState.IsFrozen = true;
  457.                         serviceState.FrozenTime = DateTime.Now;
  458.                         OnServiceFrozen?.Invoke(eventItem.ServiceId);
  459.                     }
  460.                 }
  461.             }
  462.  
  463.             // Обработка разморозки сервиса (синхронно)
  464.             private void ProcessUnfreezeService(UnfreezeServiceEvent eventItem)
  465.             {
  466.                 if (_serviceStates.ContainsKey(eventItem.ServiceId))
  467.                 {
  468.                     var serviceState = _serviceStates[eventItem.ServiceId];
  469.                     if (serviceState.IsFrozen)
  470.                     {
  471.                         serviceState.IsFrozen = false;
  472.                         serviceState.FrozenTime = null;
  473.                         OnServiceUnfrozen?.Invoke(eventItem.ServiceId);
  474.  
  475.                         int currentStep = serviceState.CurrentStep;
  476.  
  477.                         OnServiceStepChanged?.Invoke(eventItem.ServiceId, currentStep, $"Step {currentStep} completed");
  478.  
  479.                         // Проверяем, завершен ли сервис
  480.                         if (currentStep >= serviceState.TotalSteps - 1)
  481.                         {
  482.                             OnServiceCompleted?.Invoke(eventItem.ServiceId);
  483.                         }
  484.                        
  485.                         serviceState.IsStepCompleted = true;
  486.                         serviceState.IsStepRunning = false;
  487.                         serviceState.StepEndTime = DateTime.Now;
  488.                     }
  489.                 }
  490.             }
  491.            
  492.             // Обработка завершения callback-а (синхронно)
  493.             private void ProcessCallbackCompleted(CallbackCompletedEvent eventItem)
  494.             {
  495.                 eventItem.Callback.IsRunning = false;
  496.                
  497.                 if (eventItem.Success)
  498.                 {
  499.                     eventItem.Callback.IsCompleted = true;
  500.                 }
  501.                 else
  502.                 {
  503.                     // Ошибка в callback-е приводит к ошибке сервиса
  504.                     ProcessFailService(new FailServiceEvent(eventItem.Callback.ServiceId, eventItem.ErrorMessage));
  505.                 }
  506.             }
  507.            
  508.             // Логика мониторинга (синхронно, без блокировок)
  509.             private void ProcessMonitoringStep()
  510.             {
  511.                
  512.                
  513.                 // Шаг 2: Запускаем готовые сервисы
  514.                 StartReadyServices();
  515.             }
  516.  
  517.             // ИСПРАВЛЕНИЕ: Обработка callback-ов для всех сервисов (синхронно)
  518.             private void ProcessCallbacksForService(string serviceId, Dictionary<string, ServiceStepInfo> currentStates, Dictionary<int, List<ServiceCallback>> serviceCallbacks, int hiddenStep)
  519.             {
  520.                 //string serviceId = serviceCallbacks.Key;
  521.  
  522.                 // Проверяем, не заморожен ли сервис
  523.                 if (currentStates.ContainsKey(serviceId) && currentStates[serviceId].IsFrozen)
  524.                 {
  525.                     return; // Пропускаем callback'и для замороженных сервисов
  526.                 }
  527.  
  528.                 foreach (var stepCallbacks in serviceCallbacks)
  529.                 {
  530.                     int step = stepCallbacks.Key;
  531.                     var callbacks = stepCallbacks.Value;
  532.  
  533.                     foreach (var callback in callbacks)
  534.                     {
  535.                         if (!callback.IsCompleted && !callback.IsRunning)
  536.                         {
  537.                             try
  538.                             {
  539.                                 if (callback.Condition(currentStates) && hiddenStep >= callback.TargetStep)
  540.                                 {
  541.                                     callback.IsRunning = true;
  542.                                     TaskEx.RunAsync(() =>
  543.                                     {
  544.                                         try
  545.                                         {
  546.                                             callback.Callback();
  547.                                             NotifyCallbackCompleted(callback, true);
  548.                                         }
  549.                                         catch (Exception ex)
  550.                                         {
  551.                                             NotifyCallbackCompleted(callback, false,
  552.                                                 $"Error in callback execution for step {callback.TargetStep}: {ex.Message}");
  553.                                         }
  554.                                     });
  555.                                 }
  556.                             }
  557.                             catch (Exception ex)
  558.                             {
  559.                                 ProcessFailService(new FailServiceEvent(callback.ServiceId,
  560.                                     $"Error in callback condition for step {step}: {ex.Message}"));
  561.                             }
  562.                         }
  563.                     }
  564.                 }
  565.             }
  566.  
  567.             // Запуск готовых сервисов (синхронно)
  568.             private void StartReadyServices()
  569.             {
  570.                 var servicesToStart = new List<string>();
  571.                
  572.                 foreach (var kvp in _serviceStates)
  573.                 {
  574.                     var serviceId = kvp.Key;
  575.                     var serviceState = kvp.Value;
  576.                    
  577.                     if (serviceState.IsServiceFailed || serviceState.IsStepRunning || serviceState.IsFrozen) // Проверяем заморозку
  578.                         continue;
  579.                        
  580.                     int nextStep = serviceState.IsStepCompleted ? serviceState.CurrentStep + 1 : serviceState.CurrentStep;
  581.                    
  582.                     if (nextStep >= serviceState.TotalSteps)
  583.                         continue;
  584.                    
  585.                     if (IsServiceReadyForStep(serviceId, nextStep))
  586.                     {
  587.                         servicesToStart.Add(serviceId);
  588.                     }
  589.                 }
  590.                
  591.                 // Запускаем сервисы последовательно
  592.                 foreach (var serviceId in servicesToStart)
  593.                 {
  594.                     StartServiceStepSequentially(serviceId);
  595.                 }
  596.             }
  597.            
  598.             // ИСПРАВЛЕНИЕ: Проверка готовности сервиса (синхронно)
  599.             private bool IsServiceReadyForStep(string serviceId, int step)
  600.             {
  601.                 ProcessCallbacksForService(serviceId, _serviceStates, _serviceStepCallbacks[serviceId], step);
  602.  
  603.                 // ИСПРАВЛЕНИЕ: Проверяем callback'и для конкретного сервиса и шага
  604.                 if (_serviceStepCallbacks.ContainsKey(serviceId) &&
  605.                     _serviceStepCallbacks[serviceId].ContainsKey(step))
  606.                 {
  607.                     var serviceCallbacks = _serviceStepCallbacks[serviceId][step];
  608.                     if (serviceCallbacks.Any(cb => !cb.IsCompleted))
  609.                     {
  610.                         return false;
  611.                     }
  612.                 }
  613.                
  614.                 // Проверяем, что все callback'и, созданные этим сервисом, завершены
  615.                 // НО ТОЛЬКО если текущий шаг >= AuthorBlockingStep для каждого callback'а
  616.                 if (_authorCallbacks.ContainsKey(serviceId))
  617.                 {
  618.                     var authoredCallbacks = _authorCallbacks[serviceId];
  619.                    
  620.                     // Фильтруем callback'и, которые должны блокировать на данном шаге
  621.                     var blockingCallbacks = authoredCallbacks.Where(cb => step >= cb.AuthorBlockingStep).ToList();
  622.                    
  623.                     if (blockingCallbacks.Any(cb => !cb.IsCompleted && !cb.IsRunning))
  624.                     {
  625.                         // Есть незавершенные callback'и, которые должны блокировать на этом шаге
  626.                         return false;
  627.                     }
  628.                    
  629.                     if (blockingCallbacks.Any(cb => cb.IsRunning))
  630.                     {
  631.                         // Есть выполняющиеся callback'и, которые должны блокировать на этом шаге
  632.                         return false;
  633.                     }
  634.                 }
  635.                
  636.                 return true;
  637.             }
  638.            
  639.             // Последовательный запуск шага сервиса (синхронно)
  640.             private void StartServiceStepSequentially(string serviceId)
  641.             {
  642.                 if (!_serviceStates.ContainsKey(serviceId) || !_serviceSteps.ContainsKey(serviceId))
  643.                     return;
  644.                    
  645.                 var serviceState = _serviceStates[serviceId];
  646.                 var serviceSteps = _serviceSteps[serviceId];
  647.                
  648.                 if (serviceState.IsServiceFailed || serviceState.IsStepRunning || serviceState.IsFrozen) // Проверяем заморозку
  649.                     return;
  650.                
  651.                 int stepToExecute = serviceState.IsStepCompleted ? serviceState.CurrentStep + 1 : serviceState.CurrentStep;
  652.                
  653.                 if (stepToExecute >= serviceSteps.Length)
  654.                     return;
  655.                
  656.                 // Обновляем состояние сервиса
  657.                 serviceState.CurrentStep = stepToExecute;
  658.                 serviceState.IsStepCompleted = false;
  659.                 serviceState.IsStepRunning = true;
  660.                 serviceState.StepStartTime = DateTime.Now;
  661.                 serviceState.StepEndTime = null;
  662.                
  663.                 OnServiceStepChanged?.Invoke(serviceId, stepToExecute, $"Starting step {stepToExecute}");
  664.  
  665.                 // Выполняем шаг последовательно
  666.                 TaskEx.RunAsync(() =>
  667.                 {
  668.                     try
  669.                     {
  670.                         serviceSteps[stepToExecute](stepToExecute);
  671.  
  672.                         // Автоматически завершаем шаг
  673.                         //ProcessCompleteStep();
  674.                         this.CompleteCurrentStep(serviceId);
  675.                     }
  676.                     catch (Exception ex)
  677.                     {
  678.                         // ProcessFailService(new FailServiceEvent(serviceId, $"Error in step {stepToExecute}: {ex.Message}"));
  679.                         this.FailService(serviceId, $"Error in step {stepToExecute}: {ex.Message}");
  680.                     }
  681.                 });
  682.                
  683.             }
  684.            
  685.             // Получение снимка состояний (синхронно)
  686.             private Dictionary<string, ServiceStepInfo> GetCurrentStatesSnapshot()
  687.             {
  688.                 var snapshot = new Dictionary<string, ServiceStepInfo>();
  689.                 foreach (var kvp in _serviceStates)
  690.                 {
  691.                     snapshot[kvp.Key] = kvp.Value.Clone();
  692.                 }
  693.                 return snapshot;
  694.             }
  695.            
  696.             // Публичные методы для получения состояния (потокобезопасные через снимки)
  697.             public ServiceStepInfo GetServiceState(string serviceId)
  698.             {
  699.                 // Создаем событие для получения состояния и ждем результат
  700.                 // Для простоты возвращаем null, если сервис не найден
  701.                 // В production можно реализовать через отдельное событие запроса состояния
  702.                 return null;
  703.             }
  704.            
  705.             public Dictionary<string, ServiceStepInfo> GetAllServiceStates()
  706.             {
  707.                 // Аналогично, для получения полного состояния нужно отдельное событие
  708.                 return new Dictionary<string, ServiceStepInfo>();
  709.             }
  710.            
  711.             // Проверка завершения всех сервисов (синхронно)
  712.             private bool AreAllServicesCompleted()
  713.             {
  714.                 return _serviceStates.Values.All(state =>
  715.                     (state.CurrentStep >= state.TotalSteps - 1 && state.IsStepCompleted) || state.IsServiceFailed);
  716.             }
  717.            
  718.             // Информация о мониторинге
  719.             public bool IsMonitoringRunning()
  720.             {
  721.                 return _isMonitoringRunning;
  722.             }
  723.            
  724.             // УДАЛЯЕМ: GetCurrentMonitoringStep больше не актуален
  725.            
  726.             // Получение размера очереди событий
  727.             public int GetEventQueueSize()
  728.             {
  729.                 return _eventQueue.Count;
  730.             }
  731.            
  732.             // Получение информации о callback'ах автора (для отладки)
  733.             public List<ServiceCallback> GetAuthorCallbacks(string authorServiceId)
  734.             {
  735.                 return _authorCallbacks.ContainsKey(authorServiceId)
  736.                     ? new List<ServiceCallback>(_authorCallbacks[authorServiceId])
  737.                     : new List<ServiceCallback>();
  738.             }
  739.  
  740.             // Проверка заморозки сервиса
  741.             public bool IsServiceFrozen(string serviceId)
  742.             {
  743.                 return _serviceStates.ContainsKey(serviceId) && _serviceStates[serviceId].IsFrozen;
  744.             }
  745.         }
  746.        
  747.         private static readonly ServiceSynchronizationManager _syncManager = new ServiceSynchronizationManager();
  748.         public static ServiceSynchronizationManager SyncManager => _syncManager;
  749.  
  750.         private static ConcurrentHashSet<IService> AllServiceList = new ConcurrentHashSet<IService>();
  751.         private static EngineApiObjectBehaviour ServiceStorage;
  752.  
  753.         public static void StartAllServices()
  754.         {
  755.             _syncManager.StartAllServices();
  756.         }
  757.  
  758.         public static void InitializeService(IService service)
  759.         {
  760.             InitializeAllServices(new List<IService> { service });
  761.         }
  762.  
  763.         // Новые статические методы для заморозки/разморозки
  764.         public static void FreezeServiceInitialization(string serviceId)
  765.         {
  766.             _syncManager.FreezeServiceInitialization(serviceId);
  767.         }
  768.  
  769.         public static void UnfreezeServiceInitialization(string serviceId)
  770.         {
  771.             _syncManager.UnfreezeServiceInitialization(serviceId);
  772.         }
  773.  
  774.         public static void RegisterAllServices(List<Type> excludeServices = null)
  775.         {
  776. #if UNITY_5_3_OR_NEWER
  777.             ServiceStorage = new UnityEngine.GameObject("ServiceStorage").AddComponent<EngineApiObjectBehaviour>();
  778. #endif
  779. #if GODOT
  780.             ServiceStorage = new EngineApiObjectBehaviour().InitEAOB("ServiceStorage");
  781.             lock(GodotRootStorage.TreeLocker)
  782.             {
  783.                 GodotRootStorage.globalRoot.AddChild(ServiceStorage);
  784.             }
  785. #endif
  786.             if (ServiceStorage != null)
  787.                 ServiceStorage.AddComponent<ProxyMockComponent>();
  788.  
  789.             if (excludeServices == null)
  790.             {
  791.                 excludeServices = new List<Type>();
  792.             }
  793.  
  794.             AllServiceList = new ConcurrentHashSet<IService>(ECSAssemblyExtensions.GetAllSubclassOf(typeof(IService))
  795.                 .Where(x => !x.IsAbstract && !excludeServices.Contains(x))
  796.                 .Select(x => IService.InitalizeSingleton(x, ServiceStorage, true))
  797.                 .Cast<IService>()
  798.                 .ToList());
  799.                
  800.             SyncManager.OnServiceStepChanged += (serviceid, step, message) =>
  801.             {
  802.                 NLogger.LogService($"Service {serviceid} step {step}: {message}");
  803.             };
  804.             SyncManager.OnServiceFailed += (serviceid, reason) =>
  805.             {
  806.                 NLogger.LogService($"Service {serviceid} failed: {reason}");
  807.             };
  808.             SyncManager.OnServiceCompleted += (serviceid) =>
  809.             {
  810.                 NLogger.LogService($"Service {serviceid} completed");
  811.             };
  812.             SyncManager.OnAllServicesCompleted += () =>
  813.             {
  814.                 NLogger.LogService($"All services is initialized");
  815.             };
  816.             SyncManager.OnServiceFrozen += (serviceid) =>
  817.             {
  818.                 NLogger.LogService($"Service {serviceid} frozen");
  819.             };
  820.             SyncManager.OnServiceUnfrozen += (serviceid) =>
  821.             {
  822.                 NLogger.LogService($"Service {serviceid} unfrozen");
  823.             };
  824.         }
  825.  
  826.         public static void InitializeAllServices(List<IService> selectedServices = null)
  827.         {
  828.             var serviceList = selectedServices == null ? AllServiceList : new ConcurrentHashSet<IService>(selectedServices);
  829.             serviceList.ForEach(x => x.BeginInitializationProcess());
  830.             _syncManager.StartAllServices(serviceList.Count);
  831.         }
  832.  
  833.         #endregion
  834.  
  835.         // Абстрактные методы для реализации в наследниках
  836.         protected abstract Action<int>[] GetInitializationSteps();
  837.         protected abstract void SetupCallbacks(List<IService> allServices);
  838.  
  839.         // Инициализация сервиса (асинхронная регистрация через Event Loop)
  840.         public override void BeginInitializationProcess()
  841.         {
  842.             var steps = GetInitializationSteps();
  843.             var serviceId = GetSGTId();
  844.  
  845.             _syncManager.RegisterService(serviceId, steps);
  846.         }
  847.        
  848.         // Регистрация callback-а (асинхронная через Event Loop)
  849.         protected void RegisterCallback(string targetServiceId, int targetStep,
  850.             Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
  851.         {
  852.             _syncManager.RegisterCallback(targetServiceId, GetSGTId(), targetStep, authorBlockingStep, condition, callback);
  853.         }
  854.        
  855.         // Регистрация callback-а на текущий сервис (асинхронная через Event Loop)
  856.         protected void RegisterCallback(int targetStep,
  857.             Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
  858.         {
  859.             _syncManager.RegisterCallback(GetSGTId(), GetSGTId(), targetStep, authorBlockingStep, condition, callback);
  860.         }
  861.  
  862.         protected void RegisterCallbackUnsafe(string targetServiceId, int targetStep,
  863.             Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
  864.         {
  865.             _syncManager.ProcessRegisterCallback(new RegisterCallbackEvent(targetServiceId, GetSGTId(), targetStep, authorBlockingStep, condition, callback));
  866.         }
  867.  
  868.         // Регистрация callback-а на текущий сервис (асинхронная через Event Loop)
  869.         protected void RegisterCallbackUnsafe(int targetStep,
  870.             Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
  871.         {
  872.             _syncManager.ProcessRegisterCallback(new RegisterCallbackEvent(GetSGTId(), GetSGTId(), targetStep, authorBlockingStep, condition, callback));
  873.         }
  874.        
  875.         // Завершение текущего шага (асинхронное через Event Loop)
  876.         protected void CompleteCurrentStep()
  877.         {
  878.             _syncManager.CompleteCurrentStep(GetSGTId());
  879.         }
  880.  
  881.         // Методы для заморозки/разморозки текущего сервиса
  882.         protected void FreezeCurrentService()
  883.         {
  884.             _syncManager.FreezeServiceInitialization(GetSGTId());
  885.         }
  886.  
  887.         protected void UnfreezeCurrentService()
  888.         {
  889.             _syncManager.UnfreezeServiceInitialization(GetSGTId());
  890.         }
  891.  
  892.         // Проверка состояния заморозки текущего сервиса
  893.         protected bool IsCurrentServiceFrozen()
  894.         {
  895.             return _syncManager.IsServiceFrozen(GetSGTId());
  896.         }
  897.     }
  898. }
Advertisement
Add Comment
Please, Sign In to add comment