using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using log4net;
|
using Plugin.DeviceDebug.Entity;
|
using Aging.Infrastructure.Contracts;
|
|
namespace Plugin.DeviceDebug.Model
|
{
|
/// <summary>
|
/// 调试会话管理器 - 负责状态机转换和权限校验
|
/// </summary>
|
public class DebugSessionManager
|
{
|
private static readonly ILog log = LogManager.GetLogger(typeof(DebugSessionManager));
|
private readonly DeviceDebugModel _model;
|
private readonly IResourceManager? _resourceManager;
|
|
// 内存中的活跃会话缓存
|
private readonly Dictionary<string, DebugSession> _activeSessions = new();
|
|
public DebugSessionManager(DeviceDebugModel model, IResourceManager? resourceManager = null)
|
{
|
_model = model;
|
_resourceManager = resourceManager;
|
}
|
|
/// <summary>
|
/// 打开会话(ReadOnly模式)
|
/// </summary>
|
public DebugSession OpenSession(string deviceId, string operatorId, string operatorName, string effectiveVersion)
|
{
|
try
|
{
|
// 检查是否已有活跃会话
|
var existingSession = GetActiveSessionByDevice(deviceId);
|
if (existingSession != null)
|
{
|
log.Warn($"设备 {deviceId} 已有活跃会话: {existingSession.SessionId}");
|
return existingSession;
|
}
|
|
var session = new DebugSession
|
{
|
DeviceId = deviceId,
|
OperatorId = operatorId,
|
OperatorName = operatorName,
|
EffectiveVersion = effectiveVersion,
|
State = DebugSessionState.ReadOnly
|
};
|
|
// 持久化到数据库
|
_model.CreateSession(session);
|
|
// 更新内存缓存
|
_activeSessions[session.SessionId] = session;
|
|
log.Info($"打开会话: {session.SessionId}, 设备: {deviceId}, 操作员: {operatorName}");
|
return session;
|
}
|
catch (Exception ex)
|
{
|
log.Error($"打开会话失败: {ex.Message}", ex);
|
throw;
|
}
|
}
|
|
/// <summary>
|
/// 请求进入维护模式(ReadOnly → AcquiringMaintenance)
|
/// 检查:设备是否有生产Reserved
|
/// </summary>
|
public bool RequestMaintenance(string sessionId)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
return false;
|
}
|
|
// 验证状态转换
|
if (session.State != DebugSessionState.ReadOnly)
|
{
|
log.Warn($"会话 {sessionId} 当前状态为 {session.State},无法请求维护模式");
|
return false;
|
}
|
|
// 检查设备是否有生产Reserved(与资源预约系统集成)
|
if (_resourceManager != null)
|
{
|
var resourceKey = new ResourceKey(session.DeviceId, "Generic");
|
var ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
|
|
try
|
{
|
var reservation = _resourceManager.ReserveAsync(
|
ownerToken, resourceKey, CancellationToken.None).GetAwaiter().GetResult();
|
session.ReservationRef = reservation.ReservationId;
|
}
|
catch (ResourceConflictException)
|
{
|
log.Warn($"设备 {session.DeviceId} 已被生产预约占用,拒绝维护请求");
|
return false;
|
}
|
}
|
else
|
{
|
// 降级模式:无 ResourceManager 时允许所有请求(向后兼容)
|
log.Warn("ResourceManager 未初始化,跳过资源预约检查");
|
}
|
|
// 状态转换
|
session.State = DebugSessionState.AcquiringMaintenance;
|
|
// 持久化
|
_model.UpdateSession(session);
|
|
log.Info($"会话 {sessionId} 请求维护模式");
|
return true;
|
}
|
catch (Exception ex)
|
{
|
log.Error($"请求维护模式失败: {ex.Message}", ex);
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 激活维护模式(AcquiringMaintenance → MaintenanceActive)
|
/// </summary>
|
public void ActivateMaintenance(string sessionId)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
throw new InvalidOperationException($"会话不存在: {sessionId}");
|
}
|
|
// 验证状态转换
|
if (session.State != DebugSessionState.AcquiringMaintenance)
|
{
|
log.Warn($"会话 {sessionId} 当前状态为 {session.State},无法激活维护模式");
|
throw new InvalidOperationException($"会话 {sessionId} 当前状态为 {session.State},无法激活维护模式");
|
}
|
|
// 状态转换
|
session.State = DebugSessionState.MaintenanceActive;
|
|
// 持久化
|
_model.UpdateSession(session);
|
|
log.Info($"会话 {sessionId} 激活维护模式");
|
}
|
catch (Exception ex)
|
{
|
log.Error($"激活维护模式失败: {ex.Message}", ex);
|
throw;
|
}
|
}
|
|
/// <summary>
|
/// 关闭会话(MaintenanceActive → Closing → Closed)
|
/// 执行安全状态检查
|
/// </summary>
|
public void CloseSession(string sessionId)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
throw new InvalidOperationException($"会话不存在: {sessionId}");
|
}
|
|
// 验证状态转换(只有 MaintenanceActive 可以关闭)
|
if (session.State != DebugSessionState.MaintenanceActive)
|
{
|
log.Warn($"会话 {sessionId} 当前状态为 {session.State},无法关闭");
|
throw new InvalidOperationException($"会话 {sessionId} 当前状态为 {session.State},无法关闭");
|
}
|
|
// 状态转换: MaintenanceActive → Closing
|
session.State = DebugSessionState.Closing;
|
_model.UpdateSession(session);
|
log.Debug($"会话 {sessionId} 进入关闭中状态");
|
|
// 执行安全状态检查:释放资源预约
|
if (_resourceManager != null && !string.IsNullOrEmpty(session.ReservationRef))
|
{
|
try
|
{
|
var resourceKey = new ResourceKey(session.DeviceId, "Generic");
|
var ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
|
|
_resourceManager.ReleaseReservationAsync(
|
ownerToken, resourceKey, CancellationToken.None).GetAwaiter().GetResult();
|
|
log.Info($"已释放设备 {session.DeviceId} 的资源预约");
|
}
|
catch (Exception ex)
|
{
|
log.Error($"释放资源预约失败: {ex.Message}", ex);
|
// 不阻止关闭流程,但记录警告
|
}
|
}
|
|
// 状态转换: Closing → Closed
|
session.State = DebugSessionState.Closed;
|
session.ClosedAt = DateTime.Now;
|
_model.UpdateSession(session);
|
|
// 从缓存中移除
|
_activeSessions.Remove(sessionId);
|
|
log.Info($"会话 {sessionId} 已关闭");
|
}
|
catch (Exception ex)
|
{
|
log.Error($"关闭会话失败: {ex.Message}", ex);
|
throw;
|
}
|
}
|
|
/// <summary>
|
/// 故障处理(任意 → Faulted)
|
/// </summary>
|
public void FaultSession(string sessionId, string errorMessage)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
return;
|
}
|
|
// 记录当前状态
|
var previousState = session.State;
|
|
// 状态转换
|
session.State = DebugSessionState.Faulted;
|
|
// 持久化
|
_model.UpdateSession(session);
|
|
log.Error($"会话 {sessionId} 发生故障,从 {previousState} 转为 Faulted: {errorMessage}");
|
}
|
catch (Exception ex)
|
{
|
log.Error($"标记故障状态失败: {ex.Message}", ex);
|
}
|
}
|
|
/// <summary>
|
/// 标记需要恢复(任意 → RecoveryRequired)
|
/// </summary>
|
public void MarkRecoveryRequired(string sessionId)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
return;
|
}
|
|
// 记录当前状态
|
var previousState = session.State;
|
|
// 状态转换
|
session.State = DebugSessionState.RecoveryRequired;
|
|
// 持久化
|
_model.UpdateSession(session);
|
|
log.Warn($"会话 {sessionId} 标记为需要恢复,从 {previousState} 转为 RecoveryRequired");
|
}
|
catch (Exception ex)
|
{
|
log.Error($"标记恢复状态失败: {ex.Message}", ex);
|
}
|
}
|
|
/// <summary>
|
/// 验证命令是否允许执行(只有 MaintenanceActive 状态允许写操作)
|
/// </summary>
|
public bool ValidateCommand(string sessionId, DebugCommand command)
|
{
|
try
|
{
|
if (!_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
log.Warn($"会话不存在: {sessionId}");
|
return false;
|
}
|
|
// 只有 MaintenanceActive 状态允许写操作
|
bool allowed = session.State == DebugSessionState.MaintenanceActive;
|
|
if (!allowed)
|
{
|
log.Warn($"会话 {sessionId} 状态为 {session.State},拒绝执行命令: {command.CommandType}");
|
}
|
|
// 增加资源预约验证
|
if (allowed && _resourceManager != null)
|
{
|
var resourceKey = new ResourceKey(session.DeviceId, "Generic");
|
allowed = _resourceManager.ValidateOwner(
|
new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId),
|
resourceKey);
|
if (!allowed)
|
{
|
log.Warn($"会话 {sessionId} 资源预约验证失败,拒绝执行命令: {command.CommandType}");
|
}
|
}
|
|
return allowed;
|
}
|
catch (Exception ex)
|
{
|
log.Error($"验证命令失败: {ex.Message}", ex);
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 获取会话状态
|
/// </summary>
|
public DebugSessionState? GetSessionState(string sessionId)
|
{
|
try
|
{
|
if (_activeSessions.TryGetValue(sessionId, out var session))
|
{
|
return session.State;
|
}
|
|
// 从数据库查询
|
var dbSession = _model.GetSession(sessionId);
|
return dbSession?.State;
|
}
|
catch (Exception ex)
|
{
|
log.Error($"获取会话状态失败: {ex.Message}", ex);
|
return null;
|
}
|
}
|
|
/// <summary>
|
/// 获取设备当前会话(如果有)
|
/// </summary>
|
public DebugSession? GetActiveSessionByDevice(string deviceId)
|
{
|
try
|
{
|
// 先从内存缓存查找
|
var cachedSession = _activeSessions.Values
|
.FirstOrDefault(s => s.DeviceId == deviceId && s.State != DebugSessionState.Closed);
|
|
if (cachedSession != null)
|
{
|
return cachedSession;
|
}
|
|
// 从数据库查询
|
var activeSessions = _model.GetActiveSessionsByDevice(deviceId);
|
return activeSessions.FirstOrDefault();
|
}
|
catch (Exception ex)
|
{
|
log.Error($"获取设备活跃会话失败: {ex.Message}", ex);
|
return null;
|
}
|
}
|
}
|
}
|