// Copyright (c) 2026 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Logging;
using GFramework.Core.Systems;
using GFramework.Game.Abstractions.Routing;
namespace GFramework.Game.Routing;
///
/// 路由器基类,提供通用的路由管理功能
///
/// 路由项类型,必须实现 IRoute 接口
/// 路由上下文类型,必须实现 IRouteContext 接口
///
/// 此基类提供了以下通用功能:
/// - 路由守卫管理 (AddGuard/RemoveGuard)
/// - 守卫执行逻辑 (ExecuteEnterGuardsAsync/ExecuteLeaveGuardsAsync)
/// - 路由栈管理 (Stack/Current/CurrentKey)
/// - 栈操作方法 (Contains/PeekKey/IsTop)
///
public abstract class RouterBase : AbstractSystem
where TRoute : IRoute
where TContext : IRouteContext
{
private static readonly ILogger Log =
LoggerFactoryResolver.Provider.CreateLogger(nameof(RouterBase));
///
/// 路由守卫列表,按优先级排序
///
private readonly List> _guards = new();
///
/// 路由栈,用于管理路由的显示顺序和导航历史
///
protected readonly Stack Stack = new();
///
/// 获取当前路由 (栈顶元素)
///
public TRoute? Current => Stack.Count > 0 ? Stack.Peek() : default;
///
/// 获取当前路由的键值
///
public string? CurrentKey => Current?.Key;
///
/// 获取栈深度
///
public int Count => Stack.Count;
#region Abstract Methods
///
/// 注册过渡处理器 (由子类实现)
///
///
/// 子类应该在此方法中注册所有需要的过渡处理器。
/// 此方法在 OnInit 中被调用。
///
protected abstract void RegisterHandlers();
#endregion
#region Guard Management
///
/// 添加路由守卫
///
/// 路由守卫实例
/// 当守卫实例为 null 时抛出
public void AddGuard(IRouteGuard guard)
{
ArgumentNullException.ThrowIfNull(guard);
if (_guards.Contains(guard))
{
Log.Debug("Guard already registered: {0}", guard.GetType().Name);
return;
}
_guards.Add(guard);
_guards.Sort((a, b) => a.Priority.CompareTo(b.Priority));
Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority);
}
///
/// 添加路由守卫 (泛型版本)
///
/// 守卫类型,必须实现 IRouteGuard 接口且有无参构造函数
public void AddGuard() where T : IRouteGuard, new()
{
AddGuard(new T());
}
///
/// 移除路由守卫
///
/// 要移除的路由守卫实例
/// 当守卫实例为 null 时抛出
public void RemoveGuard(IRouteGuard guard)
{
ArgumentNullException.ThrowIfNull(guard);
if (_guards.Remove(guard))
Log.Debug("Guard removed: {0}", guard.GetType().Name);
}
#endregion
#region Guard Execution
///
/// 执行进入守卫检查
///
/// 路由键值
/// 路由上下文
/// 如果所有守卫都允许进入返回 true,否则返回 false
///
/// 守卫按优先级从小到大依次执行。
/// 如果某个守卫返回 false 且 CanInterrupt 为 true,则中断后续守卫的执行。
/// 如果某个守卫抛出异常且 CanInterrupt 为 true,则中断后续守卫的执行。
///
protected async Task ExecuteEnterGuardsAsync(string routeKey, TContext? context)
{
foreach (var guard in _guards)
{
try
{
Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, routeKey);
var canEnter = await guard.CanEnterAsync(routeKey, context);
if (!canEnter)
{
Log.Debug("Enter guard blocked: {0}", guard.GetType().Name);
return false;
}
if (guard.CanInterrupt)
{
Log.Debug("Enter guard {0} passed, can interrupt = true", guard.GetType().Name);
return true;
}
}
catch (Exception ex)
{
Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message);
if (guard.CanInterrupt)
return false;
}
}
return true;
}
///
/// 执行离开守卫检查
///
/// 路由键值
/// 如果所有守卫都允许离开返回 true,否则返回 false
///
/// 守卫按优先级从小到大依次执行。
/// 如果某个守卫返回 false 且 CanInterrupt 为 true,则中断后续守卫的执行。
/// 如果某个守卫抛出异常且 CanInterrupt 为 true,则中断后续守卫的执行。
///
protected async Task ExecuteLeaveGuardsAsync(string routeKey)
{
foreach (var guard in _guards)
{
try
{
Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, routeKey);
var canLeave = await guard.CanLeaveAsync(routeKey);
if (!canLeave)
{
Log.Debug("Leave guard blocked: {0}", guard.GetType().Name);
return false;
}
if (guard.CanInterrupt)
{
Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name);
return true;
}
}
catch (Exception ex)
{
Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message);
if (guard.CanInterrupt)
return false;
}
}
return true;
}
#endregion
#region Stack Operations
///
/// 检查栈中是否包含指定路由
///
/// 路由键值
/// 如果栈中包含指定路由返回 true,否则返回 false
public bool Contains(string routeKey)
{
return Stack.Any(r => r.Key == routeKey);
}
///
/// 获取栈顶路由的键值
///
/// 栈顶路由的键值,如果栈为空则返回空字符串
public string PeekKey()
{
return Stack.Count == 0 ? string.Empty : Stack.Peek().Key;
}
///
/// 判断栈顶是否为指定路由
///
/// 路由键值
/// 如果栈顶是指定路由返回 true,否则返回 false
public bool IsTop(string routeKey)
{
return Stack.Count != 0 && Stack.Peek().Key.Equals(routeKey);
}
#endregion
}