using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NECS.Core.Logging;
using NECS.ECS.ECSCore;
using NECS.Extensions;
using NECS.Extensions.ThreadingSync;
using NECS.GameEngineAPI;
namespace NECS.Harness.Model
{
public abstract
#if GODOT4_0_OR_GREATER
partial
#endif
class IService : SGT
{
#region SyncManagers
// Информация о callback-е
public class ServiceCallback
{
public string ServiceId { get; set; }
public string AuthorServiceId { get; set; } // Сервис, который создал этот callback
public int TargetStep { get; set; }
public int AuthorBlockingStep { get; set; } // Шаг, с которого начинать блокировать автора
public Func<Dictionary<string, ServiceStepInfo>, bool> Condition { get; set; }
public Action Callback { get; set; }
public bool IsCompleted { get; set; }
public bool IsRunning { get; set; }
public ServiceCallback(string serviceId, string authorServiceId, int targetStep, int authorBlockingStep, Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
{
ServiceId = serviceId;
AuthorServiceId = authorServiceId;
TargetStep = targetStep;
AuthorBlockingStep = authorBlockingStep;
Condition = condition;
Callback = callback;
IsCompleted = false;
IsRunning = false;
}
}
// Информация о состоянии шага сервиса
public class ServiceStepInfo
{
public string ServiceId { get; set; }
public int CurrentStep { get; set; }
public int TotalSteps { get; set; }
public bool IsStepCompleted { get; set; }
public bool IsServiceFailed { get; set; }
public bool IsStepRunning { get; set; }
public bool IsFrozen { get; set; } // Новое поле для отслеживания заморозки
public DateTime StepStartTime { get; set; }
public DateTime? StepEndTime { get; set; }
public DateTime? FrozenTime { get; set; } // Время заморозки
public ServiceStepInfo(string serviceId, int totalSteps)
{
ServiceId = serviceId;
CurrentStep = 0;
TotalSteps = totalSteps;
IsStepCompleted = false;
IsServiceFailed = false;
IsStepRunning = false;
IsFrozen = false;
StepStartTime = DateTime.Now;
}
public ServiceStepInfo Clone()
{
return new ServiceStepInfo(ServiceId, TotalSteps)
{
CurrentStep = this.CurrentStep,
IsStepCompleted = this.IsStepCompleted,
IsServiceFailed = this.IsServiceFailed,
IsStepRunning = this.IsStepRunning,
IsFrozen = this.IsFrozen,
StepStartTime = this.StepStartTime,
StepEndTime = this.StepEndTime,
FrozenTime = this.FrozenTime
};
}
}
// Event Loop события
public abstract class EventLoopEvent
{
public DateTime Timestamp { get; private set; }
protected EventLoopEvent()
{
Timestamp = DateTime.Now;
}
}
public class RegisterServiceEvent : EventLoopEvent
{
public string ServiceId { get; set; }
public Action<int>[] Steps { get; set; }
public RegisterServiceEvent(string serviceId, Action<int>[] steps)
{
ServiceId = serviceId;
Steps = steps;
}
}
public class RegisterCallbackEvent : EventLoopEvent
{
public string TargetServiceId { get; set; }
public string AuthorServiceId { get; set; }
public int TargetStep { get; set; }
public int AuthorBlockingStep { get; set; }
public Func<Dictionary<string, ServiceStepInfo>, bool> Condition { get; set; }
public Action Callback { get; set; }
public RegisterCallbackEvent(string targetServiceId, string authorServiceId, int targetStep, int authorBlockingStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
{
TargetServiceId = targetServiceId;
AuthorServiceId = authorServiceId;
TargetStep = targetStep;
AuthorBlockingStep = authorBlockingStep;
Condition = condition;
Callback = callback;
}
}
public class CompleteStepEvent : EventLoopEvent
{
public string ServiceId { get; set; }
public CompleteStepEvent(string serviceId)
{
ServiceId = serviceId;
}
}
public class FailServiceEvent : EventLoopEvent
{
public string ServiceId { get; set; }
public string Reason { get; set; }
public FailServiceEvent(string serviceId, string reason)
{
ServiceId = serviceId;
Reason = reason;
}
}
public class CallbackCompletedEvent : EventLoopEvent
{
public ServiceCallback Callback { get; set; }
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public CallbackCompletedEvent(ServiceCallback callback, bool success, string errorMessage = null)
{
Callback = callback;
Success = success;
ErrorMessage = errorMessage;
}
}
// Новые события для заморозки/разморозки
public class FreezeServiceEvent : EventLoopEvent
{
public string ServiceId { get; set; }
public FreezeServiceEvent(string serviceId)
{
ServiceId = serviceId;
}
}
public class UnfreezeServiceEvent : EventLoopEvent
{
public string ServiceId { get; set; }
public UnfreezeServiceEvent(string serviceId)
{
ServiceId = serviceId;
}
}
// Система синхронизации с Event Loop
public class ServiceSynchronizationManager
{
// Event Loop - потокобезопасная очередь событий
private readonly ConcurrentQueue<EventLoopEvent> _eventQueue = new ConcurrentQueue<EventLoopEvent>();
// Основное состояние (обрабатывается только в мониторинговом потоке)
private readonly Dictionary<string, ServiceStepInfo> _serviceStates = new Dictionary<string, ServiceStepInfo>();
// ИСПРАВЛЕНИЕ: Callback'и теперь индексируются по комбинации serviceId + step
private readonly Dictionary<string, Dictionary<int, List<ServiceCallback>>> _serviceStepCallbacks = new Dictionary<string, Dictionary<int, List<ServiceCallback>>>();
private readonly Dictionary<string, Action<int>[]> _serviceSteps = new Dictionary<string, Action<int>[]>();
// Отслеживание callback'ов по сервисам-авторам
private readonly Dictionary<string, List<ServiceCallback>> _authorCallbacks = new Dictionary<string, List<ServiceCallback>>();
private bool _isMonitoringRunning = false;
private bool _stopMonitoring = false;
// УДАЛЯЕМ: _currentMonitoringStep больше не нужен
// События (потокобезопасные)
public event Action<string, int, string> OnServiceStepChanged;
public event Action<string, string> OnServiceFailed;
public event Action<string> OnServiceCompleted;
public event Action OnAllServicesCompleted;
public event Action<string> OnServiceFrozen; // Новое событие
public event Action<string> OnServiceUnfrozen; // Новое событие
// Асинхронная регистрация сервиса через Event Loop
public void RegisterService(string serviceId, Action<int>[] steps)
{
_eventQueue.Enqueue(new RegisterServiceEvent(serviceId, steps));
}
// Асинхронная регистрация callback-а через Event Loop
public void RegisterCallback(string targetServiceId, string authorServiceId, int targetStep, int authorBlockingStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback)
{
_eventQueue.Enqueue(new RegisterCallbackEvent(targetServiceId, authorServiceId, targetStep, authorBlockingStep, condition, callback));
}
// Асинхронное завершение шага через Event Loop
public void CompleteCurrentStep(string serviceId)
{
_eventQueue.Enqueue(new CompleteStepEvent(serviceId));
}
// Асинхронная отметка об ошибке сервиса через Event Loop
public void FailService(string serviceId, string reason)
{
_eventQueue.Enqueue(new FailServiceEvent(serviceId, reason));
}
// Новые методы для заморозки/разморозки
public void FreezeServiceInitialization(string serviceId)
{
_eventQueue.Enqueue(new FreezeServiceEvent(serviceId));
}
public void UnfreezeServiceInitialization(string serviceId)
{
_eventQueue.Enqueue(new UnfreezeServiceEvent(serviceId));
}
// Асинхронное уведомление о завершении callback-а через Event Loop
internal void NotifyCallbackCompleted(ServiceCallback callback, bool success, string errorMessage = null)
{
_eventQueue.Enqueue(new CallbackCompletedEvent(callback, success, errorMessage));
}
// Запуск Event Loop мониторинга
public void StartAllServices(int awaitServicesCount = 0)
{
bool shouldStart = false;
// Атомарная проверка и установка флага
if (!_isMonitoringRunning)
{
_isMonitoringRunning = true;
_stopMonitoring = false;
shouldStart = true;
}
if (shouldStart)
{
TaskEx.RunAsync(() => EventLoopMonitoring(awaitServicesCount));
}
}
// Остановка мониторинга
public void StopMonitoring()
{
_stopMonitoring = true;
}
// Основной Event Loop мониторинг (выполняется в одном потоке)
private void EventLoopMonitoring(int awaitServicesCount)
{
while (!_stopMonitoring && (!AreAllServicesCompleted() || _serviceStates.Count < awaitServicesCount))
{
// Обрабатываем все события из очереди
ProcessEventQueue();
// Выполняем логику мониторинга
ProcessMonitoringStep();
// Небольшая задержка
Thread.Sleep(10);
}
// Обрабатываем оставшиеся события
ProcessEventQueue();
_isMonitoringRunning = false;
if (AreAllServicesCompleted())
{
OnAllServicesCompleted?.Invoke();
}
}
// Обработка всех событий из очереди (синхронно в мониторинговом потоке)
private void ProcessEventQueue()
{
while (_eventQueue.TryDequeue(out var eventItem))
{
ProcessEvent(eventItem);
}
}
// Обработка одного события (синхронно, без блокировок)
private void ProcessEvent(EventLoopEvent eventItem)
{
switch (eventItem)
{
case RegisterServiceEvent registerEvent:
ProcessRegisterService(registerEvent);
break;
case RegisterCallbackEvent callbackEvent:
ProcessRegisterCallback(callbackEvent);
break;
case CompleteStepEvent completeEvent:
ProcessCompleteStep(completeEvent);
break;
case FailServiceEvent failEvent:
ProcessFailService(failEvent);
break;
case CallbackCompletedEvent callbackCompletedEvent:
ProcessCallbackCompleted(callbackCompletedEvent);
break;
case FreezeServiceEvent freezeEvent:
ProcessFreezeService(freezeEvent);
break;
case UnfreezeServiceEvent unfreezeEvent:
ProcessUnfreezeService(unfreezeEvent);
break;
}
}
// Обработка регистрации сервиса (синхронно)
private void ProcessRegisterService(RegisterServiceEvent eventItem)
{
_serviceSteps[eventItem.ServiceId] = eventItem.Steps;
_serviceStates[eventItem.ServiceId] = new ServiceStepInfo(eventItem.ServiceId, eventItem.Steps.Length);
// ИСПРАВЛЕНИЕ: Инициализируем структуру callback'ов для каждого сервиса
if (!_serviceStepCallbacks.ContainsKey(eventItem.ServiceId))
{
_serviceStepCallbacks[eventItem.ServiceId] = new Dictionary<int, List<ServiceCallback>>();
}
// Инициализируем список callback'ов для этого сервиса-автора
if (!_authorCallbacks.ContainsKey(eventItem.ServiceId))
{
_authorCallbacks[eventItem.ServiceId] = new List<ServiceCallback>();
}
IService.getInstance<IService>(eventItem.ServiceId).SetupCallbacks(IService.AllServiceList.ToList());
OnServiceStepChanged?.Invoke(eventItem.ServiceId, 0, "Service registered");
}
// ИСПРАВЛЕНИЕ: Обработка регистрации callback-а (синхронно)
public void ProcessRegisterCallback(RegisterCallbackEvent eventItem)
{
// Инициализируем структуру для целевого сервиса, если её нет
if (!_serviceStepCallbacks.ContainsKey(eventItem.TargetServiceId))
{
_serviceStepCallbacks[eventItem.TargetServiceId] = new Dictionary<int, List<ServiceCallback>>();
}
// Инициализируем список для конкретного шага целевого сервиса
if (!_serviceStepCallbacks[eventItem.TargetServiceId].ContainsKey(eventItem.TargetStep))
{
_serviceStepCallbacks[eventItem.TargetServiceId][eventItem.TargetStep] = new List<ServiceCallback>();
}
var callback = new ServiceCallback(
eventItem.TargetServiceId,
eventItem.AuthorServiceId,
eventItem.TargetStep,
eventItem.AuthorBlockingStep,
eventItem.Condition,
eventItem.Callback);
_serviceStepCallbacks[eventItem.TargetServiceId][eventItem.TargetStep].Add(callback);
// Добавляем callback в список callback'ов автора
if (!_authorCallbacks.ContainsKey(eventItem.AuthorServiceId))
{
_authorCallbacks[eventItem.AuthorServiceId] = new List<ServiceCallback>();
}
_authorCallbacks[eventItem.AuthorServiceId].Add(callback);
}
// Обработка завершения шага (синхронно)
private void ProcessCompleteStep(CompleteStepEvent eventItem)
{
if (!_serviceStates.ContainsKey(eventItem.ServiceId))
return;
var serviceState = _serviceStates[eventItem.ServiceId];
if (serviceState.IsServiceFailed || serviceState.IsFrozen) // Проверяем заморозку
return;
int currentStep = serviceState.CurrentStep;
OnServiceStepChanged?.Invoke(eventItem.ServiceId, currentStep, $"Step {currentStep} completed");
// Проверяем, завершен ли сервис
if (currentStep >= serviceState.TotalSteps - 1)
{
OnServiceCompleted?.Invoke(eventItem.ServiceId);
}
serviceState.IsStepCompleted = true;
serviceState.IsStepRunning = false;
serviceState.StepEndTime = DateTime.Now;
}
// Обработка ошибки сервиса (синхронно)
private void ProcessFailService(FailServiceEvent eventItem)
{
if (_serviceStates.ContainsKey(eventItem.ServiceId))
{
_serviceStates[eventItem.ServiceId].IsServiceFailed = true;
_serviceStates[eventItem.ServiceId].IsStepRunning = false;
OnServiceFailed?.Invoke(eventItem.ServiceId, eventItem.Reason);
}
}
// Обработка заморозки сервиса (синхронно)
private void ProcessFreezeService(FreezeServiceEvent eventItem)
{
if (_serviceStates.ContainsKey(eventItem.ServiceId))
{
var serviceState = _serviceStates[eventItem.ServiceId];
if (!serviceState.IsFrozen)
{
serviceState.IsFrozen = true;
serviceState.FrozenTime = DateTime.Now;
OnServiceFrozen?.Invoke(eventItem.ServiceId);
}
}
}
// Обработка разморозки сервиса (синхронно)
private void ProcessUnfreezeService(UnfreezeServiceEvent eventItem)
{
if (_serviceStates.ContainsKey(eventItem.ServiceId))
{
var serviceState = _serviceStates[eventItem.ServiceId];
if (serviceState.IsFrozen)
{
serviceState.IsFrozen = false;
serviceState.FrozenTime = null;
OnServiceUnfrozen?.Invoke(eventItem.ServiceId);
int currentStep = serviceState.CurrentStep;
OnServiceStepChanged?.Invoke(eventItem.ServiceId, currentStep, $"Step {currentStep} completed");
// Проверяем, завершен ли сервис
if (currentStep >= serviceState.TotalSteps - 1)
{
OnServiceCompleted?.Invoke(eventItem.ServiceId);
}
serviceState.IsStepCompleted = true;
serviceState.IsStepRunning = false;
serviceState.StepEndTime = DateTime.Now;
}
}
}
// Обработка завершения callback-а (синхронно)
private void ProcessCallbackCompleted(CallbackCompletedEvent eventItem)
{
eventItem.Callback.IsRunning = false;
if (eventItem.Success)
{
eventItem.Callback.IsCompleted = true;
}
else
{
// Ошибка в callback-е приводит к ошибке сервиса
ProcessFailService(new FailServiceEvent(eventItem.Callback.ServiceId, eventItem.ErrorMessage));
}
}
// Логика мониторинга (синхронно, без блокировок)
private void ProcessMonitoringStep()
{
// Шаг 2: Запускаем готовые сервисы
StartReadyServices();
}
// ИСПРАВЛЕНИЕ: Обработка callback-ов для всех сервисов (синхронно)
private void ProcessCallbacksForService(string serviceId, Dictionary<string, ServiceStepInfo> currentStates, Dictionary<int, List<ServiceCallback>> serviceCallbacks, int hiddenStep)
{
//string serviceId = serviceCallbacks.Key;
// Проверяем, не заморожен ли сервис
if (currentStates.ContainsKey(serviceId) && currentStates[serviceId].IsFrozen)
{
return; // Пропускаем callback'и для замороженных сервисов
}
foreach (var stepCallbacks in serviceCallbacks)
{
int step = stepCallbacks.Key;
var callbacks = stepCallbacks.Value;
foreach (var callback in callbacks)
{
if (!callback.IsCompleted && !callback.IsRunning)
{
try
{
if (callback.Condition(currentStates) && hiddenStep >= callback.TargetStep)
{
callback.IsRunning = true;
TaskEx.RunAsync(() =>
{
try
{
callback.Callback();
NotifyCallbackCompleted(callback, true);
}
catch (Exception ex)
{
NotifyCallbackCompleted(callback, false,
$"Error in callback execution for step {callback.TargetStep}: {ex.Message}");
}
});
}
}
catch (Exception ex)
{
ProcessFailService(new FailServiceEvent(callback.ServiceId,
$"Error in callback condition for step {step}: {ex.Message}"));
}
}
}
}
}
// Запуск готовых сервисов (синхронно)
private void StartReadyServices()
{
var servicesToStart = new List<string>();
foreach (var kvp in _serviceStates)
{
var serviceId = kvp.Key;
var serviceState = kvp.Value;
if (serviceState.IsServiceFailed || serviceState.IsStepRunning || serviceState.IsFrozen) // Проверяем заморозку
continue;
int nextStep = serviceState.IsStepCompleted ? serviceState.CurrentStep + 1 : serviceState.CurrentStep;
if (nextStep >= serviceState.TotalSteps)
continue;
if (IsServiceReadyForStep(serviceId, nextStep))
{
servicesToStart.Add(serviceId);
}
}
// Запускаем сервисы последовательно
foreach (var serviceId in servicesToStart)
{
StartServiceStepSequentially(serviceId);
}
}
// ИСПРАВЛЕНИЕ: Проверка готовности сервиса (синхронно)
private bool IsServiceReadyForStep(string serviceId, int step)
{
ProcessCallbacksForService(serviceId, _serviceStates, _serviceStepCallbacks[serviceId], step);
// ИСПРАВЛЕНИЕ: Проверяем callback'и для конкретного сервиса и шага
if (_serviceStepCallbacks.ContainsKey(serviceId) &&
_serviceStepCallbacks[serviceId].ContainsKey(step))
{
var serviceCallbacks = _serviceStepCallbacks[serviceId][step];
if (serviceCallbacks.Any(cb => !cb.IsCompleted))
{
return false;
}
}
// Проверяем, что все callback'и, созданные этим сервисом, завершены
// НО ТОЛЬКО если текущий шаг >= AuthorBlockingStep для каждого callback'а
if (_authorCallbacks.ContainsKey(serviceId))
{
var authoredCallbacks = _authorCallbacks[serviceId];
// Фильтруем callback'и, которые должны блокировать на данном шаге
var blockingCallbacks = authoredCallbacks.Where(cb => step >= cb.AuthorBlockingStep).ToList();
if (blockingCallbacks.Any(cb => !cb.IsCompleted && !cb.IsRunning))
{
// Есть незавершенные callback'и, которые должны блокировать на этом шаге
return false;
}
if (blockingCallbacks.Any(cb => cb.IsRunning))
{
// Есть выполняющиеся callback'и, которые должны блокировать на этом шаге
return false;
}
}
return true;
}
// Последовательный запуск шага сервиса (синхронно)
private void StartServiceStepSequentially(string serviceId)
{
if (!_serviceStates.ContainsKey(serviceId) || !_serviceSteps.ContainsKey(serviceId))
return;
var serviceState = _serviceStates[serviceId];
var serviceSteps = _serviceSteps[serviceId];
if (serviceState.IsServiceFailed || serviceState.IsStepRunning || serviceState.IsFrozen) // Проверяем заморозку
return;
int stepToExecute = serviceState.IsStepCompleted ? serviceState.CurrentStep + 1 : serviceState.CurrentStep;
if (stepToExecute >= serviceSteps.Length)
return;
// Обновляем состояние сервиса
serviceState.CurrentStep = stepToExecute;
serviceState.IsStepCompleted = false;
serviceState.IsStepRunning = true;
serviceState.StepStartTime = DateTime.Now;
serviceState.StepEndTime = null;
OnServiceStepChanged?.Invoke(serviceId, stepToExecute, $"Starting step {stepToExecute}");
// Выполняем шаг последовательно
TaskEx.RunAsync(() =>
{
try
{
serviceSteps[stepToExecute](stepToExecute);
// Автоматически завершаем шаг
//ProcessCompleteStep();
this.CompleteCurrentStep(serviceId);
}
catch (Exception ex)
{
// ProcessFailService(new FailServiceEvent(serviceId, $"Error in step {stepToExecute}: {ex.Message}"));
this.FailService(serviceId, $"Error in step {stepToExecute}: {ex.Message}");
}
});
}
// Получение снимка состояний (синхронно)
private Dictionary<string, ServiceStepInfo> GetCurrentStatesSnapshot()
{
var snapshot = new Dictionary<string, ServiceStepInfo>();
foreach (var kvp in _serviceStates)
{
snapshot[kvp.Key] = kvp.Value.Clone();
}
return snapshot;
}
// Публичные методы для получения состояния (потокобезопасные через снимки)
public ServiceStepInfo GetServiceState(string serviceId)
{
// Создаем событие для получения состояния и ждем результат
// Для простоты возвращаем null, если сервис не найден
// В production можно реализовать через отдельное событие запроса состояния
return null;
}
public Dictionary<string, ServiceStepInfo> GetAllServiceStates()
{
// Аналогично, для получения полного состояния нужно отдельное событие
return new Dictionary<string, ServiceStepInfo>();
}
// Проверка завершения всех сервисов (синхронно)
private bool AreAllServicesCompleted()
{
return _serviceStates.Values.All(state =>
(state.CurrentStep >= state.TotalSteps - 1 && state.IsStepCompleted) || state.IsServiceFailed);
}
// Информация о мониторинге
public bool IsMonitoringRunning()
{
return _isMonitoringRunning;
}
// УДАЛЯЕМ: GetCurrentMonitoringStep больше не актуален
// Получение размера очереди событий
public int GetEventQueueSize()
{
return _eventQueue.Count;
}
// Получение информации о callback'ах автора (для отладки)
public List<ServiceCallback> GetAuthorCallbacks(string authorServiceId)
{
return _authorCallbacks.ContainsKey(authorServiceId)
? new List<ServiceCallback>(_authorCallbacks[authorServiceId])
: new List<ServiceCallback>();
}
// Проверка заморозки сервиса
public bool IsServiceFrozen(string serviceId)
{
return _serviceStates.ContainsKey(serviceId) && _serviceStates[serviceId].IsFrozen;
}
}
private static readonly ServiceSynchronizationManager _syncManager = new ServiceSynchronizationManager();
public static ServiceSynchronizationManager SyncManager => _syncManager;
private static ConcurrentHashSet<IService> AllServiceList = new ConcurrentHashSet<IService>();
private static EngineApiObjectBehaviour ServiceStorage;
public static void StartAllServices()
{
_syncManager.StartAllServices();
}
public static void InitializeService(IService service)
{
InitializeAllServices(new List<IService> { service });
}
// Новые статические методы для заморозки/разморозки
public static void FreezeServiceInitialization(string serviceId)
{
_syncManager.FreezeServiceInitialization(serviceId);
}
public static void UnfreezeServiceInitialization(string serviceId)
{
_syncManager.UnfreezeServiceInitialization(serviceId);
}
public static void RegisterAllServices(List<Type> excludeServices = null)
{
#if UNITY_5_3_OR_NEWER
ServiceStorage = new UnityEngine.GameObject("ServiceStorage").AddComponent<EngineApiObjectBehaviour>();
#endif
#if GODOT
ServiceStorage = new EngineApiObjectBehaviour().InitEAOB("ServiceStorage");
lock(GodotRootStorage.TreeLocker)
{
GodotRootStorage.globalRoot.AddChild(ServiceStorage);
}
#endif
if (ServiceStorage != null)
ServiceStorage.AddComponent<ProxyMockComponent>();
if (excludeServices == null)
{
excludeServices = new List<Type>();
}
AllServiceList = new ConcurrentHashSet<IService>(ECSAssemblyExtensions.GetAllSubclassOf(typeof(IService))
.Where(x => !x.IsAbstract && !excludeServices.Contains(x))
.Select(x => IService.InitalizeSingleton(x, ServiceStorage, true))
.Cast<IService>()
.ToList());
SyncManager.OnServiceStepChanged += (serviceid, step, message) =>
{
NLogger.LogService($"Service {serviceid} step {step}: {message}");
};
SyncManager.OnServiceFailed += (serviceid, reason) =>
{
NLogger.LogService($"Service {serviceid} failed: {reason}");
};
SyncManager.OnServiceCompleted += (serviceid) =>
{
NLogger.LogService($"Service {serviceid} completed");
};
SyncManager.OnAllServicesCompleted += () =>
{
NLogger.LogService($"All services is initialized");
};
SyncManager.OnServiceFrozen += (serviceid) =>
{
NLogger.LogService($"Service {serviceid} frozen");
};
SyncManager.OnServiceUnfrozen += (serviceid) =>
{
NLogger.LogService($"Service {serviceid} unfrozen");
};
}
public static void InitializeAllServices(List<IService> selectedServices = null)
{
var serviceList = selectedServices == null ? AllServiceList : new ConcurrentHashSet<IService>(selectedServices);
serviceList.ForEach(x => x.BeginInitializationProcess());
_syncManager.StartAllServices(serviceList.Count);
}
#endregion
// Абстрактные методы для реализации в наследниках
protected abstract Action<int>[] GetInitializationSteps();
protected abstract void SetupCallbacks(List<IService> allServices);
// Инициализация сервиса (асинхронная регистрация через Event Loop)
public override void BeginInitializationProcess()
{
var steps = GetInitializationSteps();
var serviceId = GetSGTId();
_syncManager.RegisterService(serviceId, steps);
}
// Регистрация callback-а (асинхронная через Event Loop)
protected void RegisterCallback(string targetServiceId, int targetStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
{
_syncManager.RegisterCallback(targetServiceId, GetSGTId(), targetStep, authorBlockingStep, condition, callback);
}
// Регистрация callback-а на текущий сервис (асинхронная через Event Loop)
protected void RegisterCallback(int targetStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
{
_syncManager.RegisterCallback(GetSGTId(), GetSGTId(), targetStep, authorBlockingStep, condition, callback);
}
protected void RegisterCallbackUnsafe(string targetServiceId, int targetStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
{
_syncManager.ProcessRegisterCallback(new RegisterCallbackEvent(targetServiceId, GetSGTId(), targetStep, authorBlockingStep, condition, callback));
}
// Регистрация callback-а на текущий сервис (асинхронная через Event Loop)
protected void RegisterCallbackUnsafe(int targetStep,
Func<Dictionary<string, ServiceStepInfo>, bool> condition, Action callback, int authorBlockingStep = 1)
{
_syncManager.ProcessRegisterCallback(new RegisterCallbackEvent(GetSGTId(), GetSGTId(), targetStep, authorBlockingStep, condition, callback));
}
// Завершение текущего шага (асинхронное через Event Loop)
protected void CompleteCurrentStep()
{
_syncManager.CompleteCurrentStep(GetSGTId());
}
// Методы для заморозки/разморозки текущего сервиса
protected void FreezeCurrentService()
{
_syncManager.FreezeServiceInitialization(GetSGTId());
}
protected void UnfreezeCurrentService()
{
_syncManager.UnfreezeServiceInitialization(GetSGTId());
}
// Проверка состояния заморозки текущего сервиса
protected bool IsCurrentServiceFrozen()
{
return _syncManager.IsServiceFrozen(GetSGTId());
}
}
}