Feature: MCP 远程控制(remote_open/close/keyboard/mouse/clipboard) #4
@@ -3193,6 +3193,11 @@ int CMcpServer::CloseScreenCtrlSession(uint64_t device_id, const std::string& se
|
|||||||
auto it = m_ScreenCtrlSessions.find(device_id);
|
auto it = m_ScreenCtrlSessions.find(device_id);
|
||||||
if (it == m_ScreenCtrlSessions.end()) return 1; // 不存在(幂等)
|
if (it == m_ScreenCtrlSessions.end()) return 1; // 不存在(幂等)
|
||||||
if (it->second.sessionId != sessionId) return 2; // token 不匹配
|
if (it->second.sessionId != sessionId) return 2; // token 不匹配
|
||||||
|
if (it->second.busy) {
|
||||||
|
// 注入在飞:置 closed 交注入线程收尾,避免与注入并发擦会话(镜像终端 busy 模式)。
|
||||||
|
it->second.closed = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (it->second.subCtx) m_ScreenCtrlContextToDevice.erase(it->second.subCtx);
|
if (it->second.subCtx) m_ScreenCtrlContextToDevice.erase(it->second.subCtx);
|
||||||
m_ScreenCtrlSessions.erase(it);
|
m_ScreenCtrlSessions.erase(it);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3205,7 +3210,7 @@ int CMcpServer::SweepIdleScreenCtrl(time_t idleTimeoutSec) {
|
|||||||
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
||||||
for (auto it = m_ScreenCtrlSessions.begin(); it != m_ScreenCtrlSessions.end(); ) {
|
for (auto it = m_ScreenCtrlSessions.begin(); it != m_ScreenCtrlSessions.end(); ) {
|
||||||
ScreenCtrlSession& s = it->second;
|
ScreenCtrlSession& s = it->second;
|
||||||
if (difftime(now, s.lastActiveAt) > (double)idleTimeoutSec) {
|
if (!s.busy && difftime(now, s.lastActiveAt) > (double)idleTimeoutSec) {
|
||||||
if (s.subCtx) m_ScreenCtrlContextToDevice.erase(s.subCtx);
|
if (s.subCtx) m_ScreenCtrlContextToDevice.erase(s.subCtx);
|
||||||
toClose.push_back(it->first);
|
toClose.push_back(it->first);
|
||||||
it = m_ScreenCtrlSessions.erase(it);
|
it = m_ScreenCtrlSessions.erase(it);
|
||||||
@@ -3226,8 +3231,49 @@ void CMcpServer::OnScreenControlClosed(context* subCtx) {
|
|||||||
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
||||||
auto it = m_ScreenCtrlContextToDevice.find(subCtx);
|
auto it = m_ScreenCtrlContextToDevice.find(subCtx);
|
||||||
if (it == m_ScreenCtrlContextToDevice.end()) return;
|
if (it == m_ScreenCtrlContextToDevice.end()) return;
|
||||||
m_ScreenCtrlSessions.erase(it->second);
|
auto sit = m_ScreenCtrlSessions.find(it->second);
|
||||||
|
if (sit == m_ScreenCtrlSessions.end()) { // 路由在但会话已擦(防御)
|
||||||
m_ScreenCtrlContextToDevice.erase(it);
|
m_ScreenCtrlContextToDevice.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sit->second.busy) {
|
||||||
|
// 注入在飞:不擦会话(注入线程仍持 subCtx),仅置 closed,由 EndScreenCtrlAction 收尾。
|
||||||
|
sit->second.closed = true;
|
||||||
|
} else {
|
||||||
|
m_ScreenCtrlSessions.erase(sit);
|
||||||
|
m_ScreenCtrlContextToDevice.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMcpServer::BeginScreenCtrlAction(uint64_t device_id, const std::string& sessionId,
|
||||||
|
context*& subCtx, int& screenW, int& screenH) {
|
||||||
|
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
||||||
|
auto it = m_ScreenCtrlSessions.find(device_id);
|
||||||
|
if (it == m_ScreenCtrlSessions.end()) return 1; // 会话不存在
|
||||||
|
ScreenCtrlSession& s = it->second;
|
||||||
|
if (s.sessionId != sessionId) return 1; // token 不匹配
|
||||||
|
if (!s.started) return 1; // 未就绪
|
||||||
|
if (s.busy) return 2; // 已有注入在飞
|
||||||
|
if (s.closed) return 1; // 子连接已断
|
||||||
|
s.busy = true;
|
||||||
|
s.lastActiveAt = time(nullptr);
|
||||||
|
subCtx = s.subCtx;
|
||||||
|
screenW = s.screenW;
|
||||||
|
screenH = s.screenH;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMcpServer::EndScreenCtrlAction(uint64_t device_id, const std::string& sessionId) {
|
||||||
|
std::lock_guard<std::mutex> lk(m_ScreenCtrlMutex);
|
||||||
|
auto it = m_ScreenCtrlSessions.find(device_id);
|
||||||
|
if (it == m_ScreenCtrlSessions.end()) return;
|
||||||
|
if (it->second.sessionId != sessionId) return;
|
||||||
|
it->second.busy = false;
|
||||||
|
it->second.lastActiveAt = time(nullptr);
|
||||||
|
if (it->second.closed) { // 注入期间子连接已断:擦会话+路由
|
||||||
|
if (it->second.subCtx) m_ScreenCtrlContextToDevice.erase(it->second.subCtx);
|
||||||
|
m_ScreenCtrlSessions.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -175,6 +175,15 @@ public:
|
|||||||
bool MarkScreenCtrlReady(uint64_t device_id, const std::string& sessionId,
|
bool MarkScreenCtrlReady(uint64_t device_id, const std::string& sessionId,
|
||||||
context* subCtx, int screenW, int screenH);
|
context* subCtx, int screenW, int screenH);
|
||||||
|
|
||||||
|
// 注入前登记(校验 sessionId/started/!busy/!closed)。输出 subCtx/screenW/H。
|
||||||
|
// 注入期间 busy=true,保证 close/sweep/断线不与注入并发擦会话(镜像终端 busy 模式,
|
||||||
|
// 评审发现 #6)。返回:0=ok;1=不存在/不匹配/未就绪/已断(-32002);2=忙(-32003)。
|
||||||
|
int BeginScreenCtrlAction(uint64_t device_id, const std::string& sessionId,
|
||||||
|
context*& subCtx, int& screenW, int& screenH);
|
||||||
|
|
||||||
|
// 注入后复位 busy;若注入期间屏幕子连接已断(closed),擦会话+路由(防泄漏)。
|
||||||
|
void EndScreenCtrlAction(uint64_t device_id, const std::string& sessionId);
|
||||||
|
|
||||||
// 关闭控制会话(校验 sessionId;擦路由 + 会话)。屏幕子连接的关闭由调用方锁外执行
|
// 关闭控制会话(校验 sessionId;擦路由 + 会话)。屏幕子连接的关闭由调用方锁外执行
|
||||||
// (CloseWebRemoteDesktopByClientID)。返回 0=已关;1=不存在(幂等);2=sessionId 不匹配。
|
// (CloseWebRemoteDesktopByClientID)。返回 0=已关;1=不存在(幂等);2=sessionId 不匹配。
|
||||||
int CloseScreenCtrlSession(uint64_t device_id, const std::string& sessionId);
|
int CloseScreenCtrlSession(uint64_t device_id, const std::string& sessionId);
|
||||||
@@ -253,6 +262,8 @@ private:
|
|||||||
std::string sessionId; // 会话 token(每次 open 独立随机)
|
std::string sessionId; // 会话 token(每次 open 独立随机)
|
||||||
context* subCtx = nullptr; // 屏幕子连接上下文(就绪后填;用于注入)
|
context* subCtx = nullptr; // 屏幕子连接上下文(就绪后填;用于注入)
|
||||||
bool started = false; // false=子连接建立中;true=已就绪
|
bool started = false; // false=子连接建立中;true=已就绪
|
||||||
|
bool busy = false; // 一条注入在飞(BeginScreenCtrlAction→End 之间)
|
||||||
|
bool closed = false; // 注入期间屏幕子连接已断(由注入线程收尾)
|
||||||
time_t lastActiveAt = 0; // idle 回收用(秒)
|
time_t lastActiveAt = 0; // idle 回收用(秒)
|
||||||
int screenW = 0; // 物理捕获分辨率(来自 TOKEN_BITMAPINFO)
|
int screenW = 0; // 物理捕获分辨率(来自 TOKEN_BITMAPINFO)
|
||||||
int screenH = 0;
|
int screenH = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user