From 559890c482f5973f06aafdfec9550fee5ba3c7f2 Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 09 十一月 2026 17:02:15 +0800
Subject: [PATCH] feat: CAN 模拟器 TCP 化 + 多设备并发调试 + 后台生命周期管理
---
Plugin.DeviceDebug/Model/DebugSessionManager.cs | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/Plugin.DeviceDebug/Model/DebugSessionManager.cs b/Plugin.DeviceDebug/Model/DebugSessionManager.cs
index 334c0b1..16cd94d 100644
--- a/Plugin.DeviceDebug/Model/DebugSessionManager.cs
+++ b/Plugin.DeviceDebug/Model/DebugSessionManager.cs
@@ -19,6 +19,20 @@
// 鍐呭瓨涓殑娲昏穬浼氳瘽缂撳瓨
private readonly Dictionary<string, DebugSession> _activeSessions = new();
+ /// <summary>
+ /// 缁存姢绉熺害蹇冭烦锛氫笌 LayeredResourceManager.DefaultTtlSeconds(300s) 瀵归綈锛�
+ /// 姣� 120s 缁湡涓�娆★紝闃叉闀挎椂闂寸淮鎶や細璇濈殑 arb.db 绉熺害杩囨湡杩涘叆 RecoveryRequired 鍚庣姝� I/O銆�
+ /// </summary>
+ private System.Threading.Timer _renewTimer;
+ private const int MaintenanceTtlSeconds = 300;
+ private const int RenewIntervalMs = 120_000;
+
+ /// <summary>
+ /// 浼氳瘽鈫掕祫婧愪护鐗岀紦瀛橈細LayeredResourceManager 鐨勭绾︽寜 TokenId 绱㈠紩锛�
+ /// 鑰� ResourceOwnerToken.TokenId 姣忔 new 閮芥槸鏂� GUID锛屽繀椤诲鐢ㄥ悓涓�瀹炰緥鎵嶈兘閲婃斁鍒扮绾�
+ /// </summary>
+ private readonly Dictionary<string, ResourceOwnerToken> _sessionOwnerTokens = new();
+
public DebugSessionManager(DeviceDebugModel model, IResourceManager? resourceManager = null)
{
_model = model;
@@ -36,8 +50,22 @@
var existingSession = GetActiveSessionByDevice(deviceId);
if (existingSession != null)
{
- log.Warn($"璁惧 {deviceId} 宸叉湁娲昏穬浼氳瘽: {existingSession.SessionId}");
- return existingSession;
+ // 杩涚▼鍐呭瓨涓瓨鍦� = 鏈細璇濈湡娲昏穬锛岀洿鎺ュ鐢�
+ if (_activeSessions.ContainsKey(existingSession.SessionId))
+ {
+ log.Warn($"璁惧 {deviceId} 宸叉湁娲昏穬浼氳瘽: {existingSession.SessionId}");
+ return existingSession;
+ }
+
+ // 浠呭瓨鍦ㄤ簬鏁版嵁搴撲笖涓嶅湪鏈繘绋嬪唴瀛� = 鏃ц繘绋嬮��鍑哄墠鐨勬畫鐣欎細璇濓細
+ // 鍏跺唴瀛樹笂涓嬫枃/缁存姢绉熺害锛坅rb.db 渚ч潬 TTL 杩囨湡+鍥炴敹锛夊凡闅忚繘绋嬫秷浜★紝
+ // 蹇呴』鍥炴敹涓� Closed 鍐嶆柊寤猴紝鍚﹀垯 RequestMaintenance 姘歌繙鈥滀細璇濅笉瀛樺湪鈥濇嫆缁�
+ _activeSessions[existingSession.SessionId] = existingSession;
+ existingSession.State = DebugSessionState.Closed;
+ existingSession.ClosedAt = DateTime.Now;
+ _model.UpdateSession(existingSession);
+ _activeSessions.Remove(existingSession.SessionId);
+ log.Warn($"宸插洖鏀惰澶� {deviceId} 鐨勬畫鐣欎細璇� {existingSession.SessionId}锛堣繘绋嬮噸鍚鑷存浼氳瘽锛夛紝鏂板缓浼氳瘽鏇夸唬");
}
var session = new DebugSession
@@ -75,8 +103,15 @@
{
if (!_activeSessions.TryGetValue(sessionId, out var session))
{
- log.Warn($"浼氳瘽涓嶅瓨鍦�: {sessionId}");
- return false;
+ // 鍏滃簳锛氫細璇濆彲鑳藉湪鏁版嵁搴擄紙濡� UI 鎸佹湁鐨� sessionID 灞炰簬閲嶅惎鍓嶆畫鐣欙級鈫� 鎭㈠杩涚紦瀛樺悗缁х画
+ session = _model.GetSession(sessionId);
+ if (session == null || session.State == DebugSessionState.Closed)
+ {
+ log.Warn($"浼氳瘽涓嶅瓨鍦�: {sessionId}");
+ return false;
+ }
+ _activeSessions[sessionId] = session;
+ log.Warn($"浼氳瘽 {sessionId} 浠庢暟鎹簱鎭㈠杩涘唴瀛樼紦瀛樺悗缁х画缁存姢璇锋眰");
}
// 楠岃瘉鐘舵�佽浆鎹�
@@ -90,7 +125,12 @@
if (_resourceManager != null)
{
var resourceKey = new ResourceKey(session.DeviceId, "Generic");
- var ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
+ // 澶嶇敤宸茬紦瀛樹护鐗岋紙娈嬬暀浼氳瘽浠� DB 鎭㈠鍚庨娆¤繘鍏ユ椂鍚屾牱鏂板缓骞跺瓨鍏ワ級
+ if (!_sessionOwnerTokens.TryGetValue(sessionId, out var ownerToken))
+ {
+ ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
+ _sessionOwnerTokens[sessionId] = ownerToken;
+ }
try
{
@@ -100,6 +140,7 @@
}
catch (ResourceConflictException)
{
+ _sessionOwnerTokens.Remove(sessionId);
log.Warn($"璁惧 {session.DeviceId} 宸茶鐢熶骇棰勭害鍗犵敤锛屾嫆缁濈淮鎶よ姹�");
return false;
}
@@ -152,6 +193,9 @@
// 鎸佷箙鍖�
_model.UpdateSession(session);
+ // 鍚姩缁存姢绉熺害蹇冭烦缁湡锛堥槻姝� TTL 杩囨湡锛�
+ EnsureRenewHeartbeat();
+
log.Info($"浼氳瘽 {sessionId} 婵�娲荤淮鎶ゆā寮�");
}
catch (Exception ex)
@@ -159,6 +203,48 @@
log.Error($"婵�娲荤淮鎶ゆā寮忓け璐�: {ex.Message}", ex);
throw;
}
+ }
+
+ /// <summary>棣栨杩涘叆缁存姢鏃跺惎鍔ㄥ懆鏈熺画鏈熷畾鏃跺櫒锛堝箓绛夛級銆�</summary>
+ private void EnsureRenewHeartbeat()
+ {
+ if (_renewTimer != null) return;
+ _renewTimer = new System.Threading.Timer(_ => RenewActiveMaintenance(),
+ null, RenewIntervalMs, RenewIntervalMs);
+ log.Info("缁存姢绉熺害蹇冭烦宸插惎鍔�");
+ }
+
+ /// <summary>鍛ㄦ湡鍥炶皟锛氬鎵�鏈� MaintenanceActive 浼氳瘽缁湡鍏� arb.db 绉熺害銆�</summary>
+ private void RenewActiveMaintenance()
+ {
+ var lrm = _resourceManager as Aging.Infrastructure.Core.LayeredResourceManager;
+ if (lrm == null) return; // 闈炲垎灞傚疄鐜帮紙鏃� Coordinator锛夋椂闄嶇骇涓嶇画鏈�
+ try
+ {
+ foreach (var kv in _activeSessions.ToArray())
+ {
+ var s = kv.Value;
+ if (s.State != DebugSessionState.MaintenanceActive) continue;
+ if (!_sessionOwnerTokens.TryGetValue(s.SessionId, out var token)) continue;
+ if (!lrm.TryGetGrants(token.TokenId, out var grants) || grants == null) continue;
+ foreach (var g in grants)
+ {
+ try { lrm.Coordinator.Renew(g, MaintenanceTtlSeconds); }
+ catch (Exception ex) { log.Warn($"缁湡璁惧 {s.DeviceId} 绉熺害澶辫触: {ex.Message}"); }
+ }
+ }
+ }
+ catch (Exception ex) { log.Error($"缁存姢绉熺害蹇冭烦寮傚父: {ex.Message}", ex); }
+ }
+
+ /// <summary>鏃犵淮鎶や腑浼氳瘽鏃跺仠姝㈠績璺筹紝閬垮厤绌鸿浆銆�</summary>
+ private void StopRenewHeartbeatIfIdle()
+ {
+ if (_renewTimer == null) return;
+ if (_activeSessions.Values.Any(s => s.State == DebugSessionState.MaintenanceActive)) return;
+ try { _renewTimer.Dispose(); } catch { }
+ _renewTimer = null;
+ log.Info("鏃犵淮鎶や腑浼氳瘽锛岀淮鎶ょ绾﹀績璺冲凡鍋滄");
}
/// <summary>
@@ -193,11 +279,17 @@
try
{
var resourceKey = new ResourceKey(session.DeviceId, "Generic");
- var ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
+ // 蹇呴』澶嶇敤杩涘叆缁存姢鏃剁殑鍚屼竴浠ょ墝瀹炰緥锛歀ayeredResourceManager 鎸� TokenId(GUID) 绱㈠紩绉熺害锛�
+ // 閲嶆柊 new 浼氬鑷� FindGrant 钀界┖銆佺绾︽案涓嶉噴鏀锯啋杩囨湡鍚� RecoveryRequired 姘镐箙闃诲鍚庣画缁存姢
+ if (!_sessionOwnerTokens.TryGetValue(sessionId, out var ownerToken))
+ {
+ ownerToken = new ResourceOwnerToken(OwnerType.Maintenance, session.SessionId);
+ }
_resourceManager.ReleaseReservationAsync(
ownerToken, resourceKey, CancellationToken.None).GetAwaiter().GetResult();
+ _sessionOwnerTokens.Remove(sessionId);
log.Info($"宸查噴鏀捐澶� {session.DeviceId} 鐨勮祫婧愰绾�");
}
catch (Exception ex)
@@ -215,6 +307,9 @@
// 浠庣紦瀛樹腑绉婚櫎
_activeSessions.Remove(sessionId);
+ // 鑻ユ棤缁存姢涓細璇濆垯鍋滄蹇冭烦
+ StopRenewHeartbeatIfIdle();
+
log.Info($"浼氳瘽 {sessionId} 宸插叧闂�");
}
catch (Exception ex)
--
Gitblit v1.9.1