cdp-tunnel 2.2.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extension-new/background.js +14 -1
- package/extension-new/cdp/handler/forward.js +2 -2
- package/extension-new/cdp/handler/special.js +2 -1
- package/extension-new/cdp/index.js +4 -4
- package/extension-new/core/debugger.js +1 -0
- package/extension-new/core/state.js +15 -0
- package/extension-new/core/websocket.js +45 -18
- package/extension-new/manifest.json +1 -1
- package/package.json +1 -1
- package/server/proxy-server.js +30 -9
|
@@ -17,6 +17,7 @@ importScripts('features/automation-badge.js');
|
|
|
17
17
|
'use strict';
|
|
18
18
|
|
|
19
19
|
var keepAliveInterval = null;
|
|
20
|
+
var _initialized = false;
|
|
20
21
|
|
|
21
22
|
function startKeepAlive() {
|
|
22
23
|
if (keepAliveInterval) {
|
|
@@ -43,6 +44,11 @@ importScripts('features/automation-badge.js');
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
function init() {
|
|
47
|
+
if (_initialized) {
|
|
48
|
+
Logger.info('[Init] Already initialized, skipping');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
_initialized = true;
|
|
46
52
|
Logger.info('[Init] CDP Bridge starting...');
|
|
47
53
|
|
|
48
54
|
// 点击扩展图标时打开配置页面
|
|
@@ -118,11 +124,11 @@ importScripts('features/automation-badge.js');
|
|
|
118
124
|
var sessionId = State.findSessionByTabId(tabId);
|
|
119
125
|
if (sessionId) {
|
|
120
126
|
var targetId = State.getTargetIdBySession(sessionId);
|
|
121
|
-
EventBuilder.send('Target.targetDestroyed', { targetId: targetId });
|
|
122
127
|
EventBuilder.send('Target.detachedFromTarget', {
|
|
123
128
|
sessionId: sessionId,
|
|
124
129
|
targetId: targetId
|
|
125
130
|
});
|
|
131
|
+
EventBuilder.send('Target.targetDestroyed', { targetId: targetId });
|
|
126
132
|
State.unmapSession(sessionId);
|
|
127
133
|
if (removedClientId) {
|
|
128
134
|
SpecialHandler.updateTabGroupName(removedClientId);
|
|
@@ -132,6 +138,7 @@ importScripts('features/automation-badge.js');
|
|
|
132
138
|
if (State.getCurrentTabId() === tabId) {
|
|
133
139
|
State.persist(null, false);
|
|
134
140
|
}
|
|
141
|
+
State.removeTabIdToClientId(tabId);
|
|
135
142
|
});
|
|
136
143
|
|
|
137
144
|
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
|
@@ -204,6 +211,12 @@ importScripts('features/automation-badge.js');
|
|
|
204
211
|
|
|
205
212
|
var sessionId = CDPUtils.generateSessionId();
|
|
206
213
|
State.mapSession(sessionId, tabId, targetId);
|
|
214
|
+
|
|
215
|
+
var openerClientId = openerTabId ? State.getClientIdByTabId(openerTabId) : null;
|
|
216
|
+
if (openerClientId) {
|
|
217
|
+
State.setTabIdToClientId(tabId, openerClientId);
|
|
218
|
+
Logger.info('[Tabs] Mapped child tab', tabId, '-> clientId:', openerClientId);
|
|
219
|
+
}
|
|
207
220
|
|
|
208
221
|
Config.getAutoMute(function(enabled) {
|
|
209
222
|
if (enabled) {
|
|
@@ -9,12 +9,12 @@ var ForwardHandler = (function() {
|
|
|
9
9
|
|
|
10
10
|
if (!tabId) {
|
|
11
11
|
Logger.warn('[Forward] No tabId for command:', method);
|
|
12
|
-
return Promise.
|
|
12
|
+
return Promise.reject({ code: -32000, message: 'No target found for command: ' + method });
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
if (!State.isTabAttached(tabId)) {
|
|
16
16
|
Logger.warn('[Forward] Tab not attached, skipping command:', method, 'tabId:', tabId);
|
|
17
|
-
return Promise.
|
|
17
|
+
return Promise.reject({ code: -32000, message: 'Target is not attached' });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
Logger.debug('[Forward]', method, '-> tabId:', tabId);
|
|
@@ -228,16 +228,17 @@ var SpecialHandler = (function() {
|
|
|
228
228
|
if (targetId) {
|
|
229
229
|
var tabId = State.getTabIdByTargetId(targetId);
|
|
230
230
|
if (tabId) {
|
|
231
|
-
State.removeAttachedTab(tabId);
|
|
232
231
|
var closeClientId = State.getClientIdByTabId(tabId);
|
|
233
232
|
return new Promise(function(resolve) {
|
|
234
233
|
chrome.tabs.remove(tabId, function() {
|
|
234
|
+
State.removeAttachedTab(tabId);
|
|
235
235
|
if (closeClientId) {
|
|
236
236
|
updateTabGroupName(closeClientId);
|
|
237
237
|
}
|
|
238
238
|
resolve({ success: true });
|
|
239
239
|
});
|
|
240
240
|
}).catch(function() {
|
|
241
|
+
State.removeAttachedTab(tabId);
|
|
241
242
|
return { success: true };
|
|
242
243
|
});
|
|
243
244
|
}
|
|
@@ -82,8 +82,8 @@ function routeCDPCommand(message) {
|
|
|
82
82
|
resolve({ result: result });
|
|
83
83
|
})
|
|
84
84
|
.catch(function(error) {
|
|
85
|
-
Logger.error('[CDP] ERROR id=' + id + ' method=' + method + ' msg=' + error.message);
|
|
86
|
-
resolve({ error: { message: error.message } });
|
|
85
|
+
Logger.error('[CDP] ERROR id=' + id + ' method=' + method + ' msg=' + (error.message || error));
|
|
86
|
+
resolve({ error: { code: error.code || -32000, message: error.message || String(error) } });
|
|
87
87
|
});
|
|
88
88
|
} else {
|
|
89
89
|
ForwardHandler.execute({ id: id, method: method, params: params, sessionId: sessionId, clientId: clientId })
|
|
@@ -92,8 +92,8 @@ function routeCDPCommand(message) {
|
|
|
92
92
|
resolve({ result: result });
|
|
93
93
|
})
|
|
94
94
|
.catch(function(error) {
|
|
95
|
-
Logger.error('[CDP] ERROR id=' + id + ' method=' + method + ' msg=' + error.message + ' (forwarded)');
|
|
96
|
-
resolve({ error: { message: error.message } });
|
|
95
|
+
Logger.error('[CDP] ERROR id=' + id + ' method=' + method + ' msg=' + (error.message || error) + ' (forwarded)');
|
|
96
|
+
resolve({ error: { code: error.code || -32000, message: error.message || String(error) } });
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
}).then(function(response) {
|
|
@@ -38,6 +38,9 @@ var State = (function() {
|
|
|
38
38
|
var tabId = _state.sessionIdToTabId.get(sessionId);
|
|
39
39
|
_state.sessionIdToTabId.delete(sessionId);
|
|
40
40
|
_state.sessionIdToTargetId.delete(sessionId);
|
|
41
|
+
if (tabId && !hasOtherSessionForTab(tabId)) {
|
|
42
|
+
_state.attachedTabIds.delete(tabId);
|
|
43
|
+
}
|
|
41
44
|
return tabId;
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -254,6 +257,7 @@ var State = (function() {
|
|
|
254
257
|
function clearAllState() {
|
|
255
258
|
clearSessionState();
|
|
256
259
|
_state.attachedTabIds.clear();
|
|
260
|
+
_state.emittedTargets.clear();
|
|
257
261
|
_state.screencastPollingSessions.clear();
|
|
258
262
|
_state.browserContextIds = new Set(['default']);
|
|
259
263
|
_state.autoAttachConfig = {
|
|
@@ -265,7 +269,13 @@ var State = (function() {
|
|
|
265
269
|
_state.hasConnectedClient = false;
|
|
266
270
|
_state.tabIdToClientId.clear();
|
|
267
271
|
_state.clientIdToGroupId.clear();
|
|
272
|
+
_state.clientIdToTabId.clear();
|
|
273
|
+
_state.clientIdToSessionId.clear();
|
|
268
274
|
_state.preExistingTabIds.clear();
|
|
275
|
+
_state.pendingDebuggerTabs.clear();
|
|
276
|
+
_state.automatedTabs.clear();
|
|
277
|
+
_state.pendingCreatedTabUrls.clear();
|
|
278
|
+
_state.cdpClients = [];
|
|
269
279
|
}
|
|
270
280
|
|
|
271
281
|
function cleanupAllTabs() {
|
|
@@ -332,6 +342,10 @@ var State = (function() {
|
|
|
332
342
|
_state.tabIdToClientId.set(tabId, clientId);
|
|
333
343
|
}
|
|
334
344
|
|
|
345
|
+
function removeTabIdToClientId(tabId) {
|
|
346
|
+
_state.tabIdToClientId.delete(tabId);
|
|
347
|
+
}
|
|
348
|
+
|
|
335
349
|
function getClientIdByTabId(tabId) {
|
|
336
350
|
return _state.tabIdToClientId.get(tabId);
|
|
337
351
|
}
|
|
@@ -471,6 +485,7 @@ var State = (function() {
|
|
|
471
485
|
clearAllState: clearAllState,
|
|
472
486
|
cleanupAllTabs: cleanupAllTabs,
|
|
473
487
|
setTabIdToClientId: setTabIdToClientId,
|
|
488
|
+
removeTabIdToClientId: removeTabIdToClientId,
|
|
474
489
|
getClientIdByTabId: getClientIdByTabId,
|
|
475
490
|
setGroupIdForClient: setGroupIdForClient,
|
|
476
491
|
getGroupIdForClient: getGroupIdForClient,
|
|
@@ -339,16 +339,20 @@ var WebSocketManager = (function() {
|
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
341
|
Logger.info('[WS] Closing ' + tabIds.length + ' attached tabs for clientId:', clientId);
|
|
342
|
+
var pending = tabIds.length;
|
|
342
343
|
tabIds.forEach(function(tabId) {
|
|
343
344
|
chrome.tabs.remove(tabId, function() {
|
|
344
345
|
if (chrome.runtime.lastError) {
|
|
345
346
|
Logger.info('[WS] Tab already closed:', tabId);
|
|
346
347
|
}
|
|
348
|
+
chrome.debugger.detach({ tabId: tabId }).catch(function() {});
|
|
349
|
+
State.removeAttachedTab(tabId);
|
|
350
|
+
pending--;
|
|
351
|
+
if (pending === 0) {
|
|
352
|
+
resolve();
|
|
353
|
+
}
|
|
347
354
|
});
|
|
348
|
-
chrome.debugger.detach({ tabId: tabId }).catch(function() {});
|
|
349
|
-
State.removeAttachedTab(tabId);
|
|
350
355
|
});
|
|
351
|
-
resolve();
|
|
352
356
|
}
|
|
353
357
|
|
|
354
358
|
function handleServerRestart() {
|
|
@@ -372,17 +376,27 @@ var WebSocketManager = (function() {
|
|
|
372
376
|
Logger.info('[WS] Browser.close received, cleaning up... clientId:', clientId);
|
|
373
377
|
|
|
374
378
|
closeTabGroupByClientId(clientId).then(function() {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
379
|
+
return new Promise(function(resolve) {
|
|
380
|
+
closeTabsByClientId(clientId, resolve);
|
|
381
|
+
});
|
|
382
|
+
}).then(function() {
|
|
383
|
+
var preExistingTabs = State.getPreExistingTabs();
|
|
384
|
+
var clientPreExisting = preExistingTabs.filter(function(tabId) {
|
|
385
|
+
return State.getClientIdByTabId(tabId) === clientId;
|
|
380
386
|
});
|
|
381
|
-
|
|
387
|
+
clientPreExisting.forEach(function(tabId) {
|
|
388
|
+
chrome.debugger.detach({ tabId: tabId }).catch(function() {});
|
|
389
|
+
State.removeAttachedTab(tabId);
|
|
390
|
+
});
|
|
391
|
+
State.clearPreExistingTabsForClient(clientId);
|
|
392
|
+
|
|
393
|
+
State.removeCDPClient(clientId);
|
|
394
|
+
if (State.getCDPClients().length === 0) {
|
|
382
395
|
State.clearAllState();
|
|
383
396
|
State.persist(null, false);
|
|
384
|
-
|
|
385
|
-
|
|
397
|
+
}
|
|
398
|
+
broadcastStateUpdate();
|
|
399
|
+
Logger.info('[WS] Browser.close cleanup complete for client:', clientId);
|
|
386
400
|
});
|
|
387
401
|
}
|
|
388
402
|
|
|
@@ -398,7 +412,18 @@ var WebSocketManager = (function() {
|
|
|
398
412
|
var cdpClients = State.getCDPClients() || [];
|
|
399
413
|
var attachedTabIds = State.getAttachedTabIds();
|
|
400
414
|
|
|
415
|
+
if (attachedTabIds.length === 0) {
|
|
416
|
+
chrome.runtime.sendMessage({
|
|
417
|
+
type: 'stateUpdate',
|
|
418
|
+
connected: isConnected,
|
|
419
|
+
cdpClients: cdpClients,
|
|
420
|
+
attachedPages: []
|
|
421
|
+
}).catch(function() {});
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
401
425
|
var attachedPages = [];
|
|
426
|
+
var pending = attachedTabIds.length;
|
|
402
427
|
attachedTabIds.forEach(function(tabId) {
|
|
403
428
|
chrome.tabs.get(tabId, function(tab) {
|
|
404
429
|
if (tab && !chrome.runtime.lastError) {
|
|
@@ -408,15 +433,17 @@ var WebSocketManager = (function() {
|
|
|
408
433
|
url: tab.url || ''
|
|
409
434
|
});
|
|
410
435
|
}
|
|
436
|
+
pending--;
|
|
437
|
+
if (pending === 0) {
|
|
438
|
+
chrome.runtime.sendMessage({
|
|
439
|
+
type: 'stateUpdate',
|
|
440
|
+
connected: isConnected,
|
|
441
|
+
cdpClients: cdpClients,
|
|
442
|
+
attachedPages: attachedPages
|
|
443
|
+
}).catch(function() {});
|
|
444
|
+
}
|
|
411
445
|
});
|
|
412
446
|
});
|
|
413
|
-
|
|
414
|
-
chrome.runtime.sendMessage({
|
|
415
|
-
type: 'stateUpdate',
|
|
416
|
-
connected: isConnected,
|
|
417
|
-
cdpClients: cdpClients,
|
|
418
|
-
attachedPages: attachedPages
|
|
419
|
-
}).catch(function() {});
|
|
420
447
|
}
|
|
421
448
|
|
|
422
449
|
function getQueueStats() {
|
package/package.json
CHANGED
package/server/proxy-server.js
CHANGED
|
@@ -506,8 +506,14 @@ function handlePluginConnection(ws, clientInfo) {
|
|
|
506
506
|
const sessionId = parsed.params?.sessionId;
|
|
507
507
|
|
|
508
508
|
if (targetId && sessionId) {
|
|
509
|
-
|
|
510
|
-
|
|
509
|
+
const clientId = ws.pairedClientId;
|
|
510
|
+
if (clientId) {
|
|
511
|
+
sessionToClientId.set(sessionId, clientId);
|
|
512
|
+
console.log(`[SESSION MAPPED] sessionId=${sessionId?.substring(0,8) || 'none'} -> clientId=${clientId?.substring(0,8) || 'none'}`);
|
|
513
|
+
} else {
|
|
514
|
+
sessionToClientId.set(sessionId, targetId);
|
|
515
|
+
console.log(`[SESSION MAPPED] sessionId=${sessionId?.substring(0,8) || 'none'} -> targetId=${targetId?.substring(0,8) || 'none'} (no pairedClientId)`);
|
|
516
|
+
}
|
|
511
517
|
}
|
|
512
518
|
}
|
|
513
519
|
|
|
@@ -559,6 +565,12 @@ function handlePluginConnection(ws, clientInfo) {
|
|
|
559
565
|
console.log(`[BROWSER CONTEXT MAPPED] browserContextId=${browserContextId} -> clientId=${mapping.clientId}`);
|
|
560
566
|
}
|
|
561
567
|
|
|
568
|
+
// 如果是 Target.attachToTarget 响应,建立 sessionId -> clientId 映射
|
|
569
|
+
if (parsed.result?.sessionId && mapping.method === 'Target.attachToTarget') {
|
|
570
|
+
sessionToClientId.set(parsed.result.sessionId, mapping.clientId);
|
|
571
|
+
console.log(`[SESSION MAPPED from attach response] sessionId=${parsed.result.sessionId?.substring(0,8)} -> clientId=${mapping.clientId?.substring(0,8)}`);
|
|
572
|
+
}
|
|
573
|
+
|
|
562
574
|
// 如果是 Target.createTarget 响应,先发送缓存的 Target.attachedToTarget 事件
|
|
563
575
|
// 然后再发送响应
|
|
564
576
|
if (mapping.isCreateTarget && parsed.result?.targetId) {
|
|
@@ -867,7 +879,8 @@ function handleClientConnection(ws, clientInfo, customClientId = null) {
|
|
|
867
879
|
globalRequestIdMap.set(globalId, {
|
|
868
880
|
clientId: id,
|
|
869
881
|
originalId: originalId,
|
|
870
|
-
sessionId: parsed.sessionId
|
|
882
|
+
sessionId: parsed.sessionId,
|
|
883
|
+
method: parsed.method
|
|
871
884
|
});
|
|
872
885
|
|
|
873
886
|
// 修改请求ID为全局ID
|
|
@@ -877,12 +890,6 @@ function handleClientConnection(ws, clientInfo, customClientId = null) {
|
|
|
877
890
|
console.log(`[REQUEST ID MAPPED] client=${id} original=${originalId} -> global=${globalId} sessionId=${parsed.sessionId?.substring(0,8) || 'none'}`);
|
|
878
891
|
}
|
|
879
892
|
|
|
880
|
-
// 记录 Target.attachToTarget 请求,用于后续建立 session -> clientId 映射
|
|
881
|
-
if (parsed && parsed.method === 'Target.attachToTarget' && parsed.id !== undefined) {
|
|
882
|
-
pendingAttachRequests.set(parsed.id, id);
|
|
883
|
-
console.log(`[PENDING ATTACH] Request id=${parsed.id} from client=${id}, pending size=${pendingAttachRequests.size}`);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
893
|
// 记录 Target.createTarget 请求,用于后续建立 targetId -> clientId 映射
|
|
887
894
|
// 注意:此时 parsed.id 已经是 globalId,originalId 已经保存在 mapping 中
|
|
888
895
|
if (parsed && parsed.method === 'Target.createTarget' && parsed.id !== undefined) {
|
|
@@ -1010,6 +1017,20 @@ function handleClientConnection(ws, clientInfo, customClientId = null) {
|
|
|
1010
1017
|
// 广播更新后的客户端列表
|
|
1011
1018
|
broadcastClientList();
|
|
1012
1019
|
|
|
1020
|
+
// 清理该 client 的所有映射
|
|
1021
|
+
for (const [tId, cId] of targetIdToClientId.entries()) {
|
|
1022
|
+
if (cId === id) targetIdToClientId.delete(tId);
|
|
1023
|
+
}
|
|
1024
|
+
for (const [bcId, cId] of browserContextToClientId.entries()) {
|
|
1025
|
+
if (cId === id) browserContextToClientId.delete(bcId);
|
|
1026
|
+
}
|
|
1027
|
+
if (clientIdToBrowserContext.has(id)) {
|
|
1028
|
+
clientIdToBrowserContext.delete(id);
|
|
1029
|
+
}
|
|
1030
|
+
for (const [gId, mapping] of globalRequestIdMap.entries()) {
|
|
1031
|
+
if (mapping.clientId === id) globalRequestIdMap.delete(gId);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1013
1034
|
// 清理配对关系
|
|
1014
1035
|
if (ws.pairedPlugin) {
|
|
1015
1036
|
ws.pairedPlugin.pairedClientId = null;
|