feat(task-0002): implement state controller interface with cancellation support and update task status
- Refactor BootStatesController to implement IStatesController interface - Move state dictionary creation into constructor, remove static helper method - Add CancellationToken validation before state transitions in StatesController - Track current state presence with _hasCurrentState flag for safety - Update TASK-0002 with Ready status Выполнена задача TASK-0002 и обновлён статус: - Рефакторинг BootStatesController для реализации интерфейса IStatesController - Перемещено создание словаря состояний в конструктор, удалён статический вспомогательный метод - Добавлена валидация CancellationToken перед переходами между состояниями в StatesController - Добавлен флаг _hasCurrentState для отслеживания текущего состояния - Обновлён статус TASK-0002 до Ready
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# TASK-0002: Базовая архитектура Boot Flow
|
# TASK-0002: Базовая архитектура Boot Flow
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
|
||||||
|
Ready
|
||||||
|
|
||||||
## Цель
|
## Цель
|
||||||
|
|
||||||
Создать минимальную архитектурную основу для boot flow: сервисный lifecycle, state-контракты и generic state controller.
|
Создать минимальную архитектурную основу для boot flow: сервисный lifecycle, state-контракты и generic state controller.
|
||||||
|
|||||||
@@ -1,29 +1,31 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
using QuizPleaseTest.Common.StateMachine;
|
using QuizPleaseTest.Common.StateMachine;
|
||||||
|
|
||||||
namespace QuizPleaseTest.Boot.States
|
namespace QuizPleaseTest.Boot.States
|
||||||
{
|
{
|
||||||
public class BootStatesController : StatesController<BootStateCode>
|
public class BootStatesController : IStatesController<BootStateCode>
|
||||||
{
|
{
|
||||||
|
private readonly StatesController<BootStateCode> _statesController;
|
||||||
|
|
||||||
public BootStatesController(
|
public BootStatesController(
|
||||||
SplashState splashState,
|
SplashState splashState,
|
||||||
LoadState loadState,
|
LoadState loadState,
|
||||||
MenuState menuState)
|
MenuState menuState)
|
||||||
: base(CreateStates(splashState, loadState, menuState))
|
|
||||||
{
|
{
|
||||||
}
|
_statesController = new StatesController<BootStateCode>(
|
||||||
|
new Dictionary<BootStateCode, IState>
|
||||||
private static IReadOnlyDictionary<BootStateCode, IState> CreateStates(
|
|
||||||
SplashState splashState,
|
|
||||||
LoadState loadState,
|
|
||||||
MenuState menuState)
|
|
||||||
{
|
|
||||||
return new Dictionary<BootStateCode, IState>
|
|
||||||
{
|
{
|
||||||
{ BootStateCode.Splash, splashState },
|
{ BootStateCode.Splash, splashState },
|
||||||
{ BootStateCode.Load, loadState },
|
{ BootStateCode.Load, loadState },
|
||||||
{ BootStateCode.Menu, menuState }
|
{ BootStateCode.Menu, menuState }
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask EnterStateAsync(BootStateCode code, CancellationToken ct)
|
||||||
|
{
|
||||||
|
return _statesController.EnterStateAsync(code, ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace QuizPleaseTest.Common.StateMachine
|
|||||||
{
|
{
|
||||||
private readonly IReadOnlyDictionary<TEnum, IState> _states;
|
private readonly IReadOnlyDictionary<TEnum, IState> _states;
|
||||||
private IState _currentState;
|
private IState _currentState;
|
||||||
|
private bool _hasCurrentState;
|
||||||
|
|
||||||
public StatesController(IReadOnlyDictionary<TEnum, IState> states)
|
public StatesController(IReadOnlyDictionary<TEnum, IState> states)
|
||||||
{
|
{
|
||||||
@@ -17,18 +18,25 @@ namespace QuizPleaseTest.Common.StateMachine
|
|||||||
|
|
||||||
public async UniTask EnterStateAsync(TEnum code, CancellationToken ct)
|
public async UniTask EnterStateAsync(TEnum code, CancellationToken ct)
|
||||||
{
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
if (!_states.TryGetValue(code, out IState newState))
|
if (!_states.TryGetValue(code, out IState newState))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"State is not registered: {code}");
|
throw new InvalidOperationException($"State is not registered: {code}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentState != null)
|
if (_hasCurrentState)
|
||||||
{
|
{
|
||||||
await _currentState.ExitAsync(ct);
|
await _currentState.ExitAsync(ct);
|
||||||
|
_currentState = null;
|
||||||
|
_hasCurrentState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await newState.EnterAsync(ct);
|
||||||
_currentState = newState;
|
_currentState = newState;
|
||||||
await _currentState.EnterAsync(ct);
|
_hasCurrentState = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user