cdp-tunnel 2.7.9 → 2.8.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 +234 -130
- package/extension-new/cdp/handler/forward.js +9 -7
- package/extension-new/cdp/handler/local.js +60 -39
- package/extension-new/cdp/handler/special.js +145 -119
- package/extension-new/cdp/index.js +16 -7
- package/extension-new/cdp/response.js +12 -4
- package/extension-new/config-page-preview.html +174 -57
- package/extension-new/config-page.js +169 -70
- package/extension-new/core/connection-manager.js +120 -0
- package/extension-new/core/connection-state.js +355 -0
- package/extension-new/core/debugger.js +65 -52
- package/extension-new/core/state.js +87 -438
- package/extension-new/core/websocket.js +345 -279
- package/extension-new/features/screencast.js +42 -20
- package/extension-new/manifest.json +3 -2
- package/extension-new/utils/config.js +83 -2
- package/extension-new/utils/helpers.js +5 -4
- package/package.json +1 -1
|
@@ -3,6 +3,8 @@ importScripts('utils/logger.js');
|
|
|
3
3
|
importScripts('utils/helpers.js');
|
|
4
4
|
importScripts('utils/diagnostics.js');
|
|
5
5
|
importScripts('core/state.js');
|
|
6
|
+
importScripts('core/connection-state.js');
|
|
7
|
+
importScripts('core/connection-manager.js');
|
|
6
8
|
importScripts('core/websocket.js');
|
|
7
9
|
importScripts('core/debugger.js');
|
|
8
10
|
importScripts('cdp/response.js');
|
|
@@ -23,12 +25,14 @@ importScripts('features/automation-badge.js');
|
|
|
23
25
|
if (keepAliveInterval) {
|
|
24
26
|
clearInterval(keepAliveInterval);
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
|
|
27
29
|
keepAliveInterval = setInterval(function() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
ConnectionManager.forEachConnection(function(entry) {
|
|
31
|
+
var ws = entry.state.getWs();
|
|
32
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
33
|
+
entry.wsManager.send({ type: 'keepalive', timestamp: Date.now() });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
32
36
|
}, 20000);
|
|
33
37
|
|
|
34
38
|
chrome.alarms.clear('sw-keepalive', function() {
|
|
@@ -52,7 +56,6 @@ importScripts('features/automation-badge.js');
|
|
|
52
56
|
_initialized = true;
|
|
53
57
|
Logger.info('[Init] CDP Bridge starting...');
|
|
54
58
|
|
|
55
|
-
// 点击扩展图标时打开配置页面
|
|
56
59
|
chrome.action.onClicked.addListener(function(tab) {
|
|
57
60
|
Logger.info('[Action] Extension icon clicked, opening config page');
|
|
58
61
|
chrome.tabs.create({
|
|
@@ -67,12 +70,22 @@ importScripts('features/automation-badge.js');
|
|
|
67
70
|
validatePersistedState(result.currentTabId, result.isAttached);
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
Config.getConnections(function(connections) {
|
|
74
|
+
ConnectionManager.init(connections);
|
|
75
|
+
|
|
76
|
+
var primary = ConnectionManager.getPrimaryConnection();
|
|
77
|
+
if (primary && result.currentTabId != null) {
|
|
78
|
+
primary.state.currentTabId = result.currentTabId;
|
|
79
|
+
primary.state.isAttached = result.isAttached;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
ConnectionManager.connectAll();
|
|
83
|
+
startKeepAlive();
|
|
84
|
+
|
|
85
|
+
setTimeout(function() {
|
|
86
|
+
Diagnostics.start();
|
|
87
|
+
}, 2000);
|
|
88
|
+
});
|
|
76
89
|
});
|
|
77
90
|
}
|
|
78
91
|
|
|
@@ -117,29 +130,37 @@ importScripts('features/automation-badge.js');
|
|
|
117
130
|
chrome.tabs.onRemoved.addListener(function(tabId) {
|
|
118
131
|
Logger.info('[Tabs] Tab removed:', tabId);
|
|
119
132
|
|
|
120
|
-
|
|
121
|
-
var
|
|
122
|
-
|
|
133
|
+
var entry = ConnectionManager.getConnectionByTabId(tabId);
|
|
134
|
+
var state = entry ? entry.state : null;
|
|
135
|
+
var wsManager = entry ? entry.wsManager : null;
|
|
136
|
+
|
|
137
|
+
if (state) {
|
|
138
|
+
state.removeAttachedTab(tabId);
|
|
139
|
+
}
|
|
140
|
+
var removedClientId = state ? state.getClientIdByTabId(tabId) : null;
|
|
141
|
+
Screencast.stopPolling(tabId, state);
|
|
123
142
|
AutomationBadge.remove(tabId);
|
|
124
143
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
144
|
+
if (state) {
|
|
145
|
+
var sessionId = state.findSessionByTabId(tabId);
|
|
146
|
+
if (sessionId) {
|
|
147
|
+
var targetId = state.getTargetIdBySession(sessionId);
|
|
148
|
+
EventBuilder.send('Target.detachedFromTarget', {
|
|
149
|
+
sessionId: sessionId,
|
|
150
|
+
targetId: targetId
|
|
151
|
+
}, null, wsManager);
|
|
152
|
+
EventBuilder.send('Target.targetDestroyed', { targetId: targetId }, null, wsManager);
|
|
153
|
+
state.unmapSession(sessionId);
|
|
154
|
+
if (removedClientId) {
|
|
155
|
+
SpecialHandler.updateTabGroupName(removedClientId, state, wsManager);
|
|
156
|
+
}
|
|
136
157
|
}
|
|
137
|
-
}
|
|
138
158
|
|
|
139
|
-
|
|
140
|
-
|
|
159
|
+
if (state.getCurrentTabId() === tabId) {
|
|
160
|
+
state.persist(null, false);
|
|
161
|
+
}
|
|
162
|
+
state.removeTabIdToClientId(tabId);
|
|
141
163
|
}
|
|
142
|
-
State.removeTabIdToClientId(tabId);
|
|
143
164
|
});
|
|
144
165
|
|
|
145
166
|
if (chrome.tabGroups) {
|
|
@@ -148,47 +169,59 @@ importScripts('features/automation-badge.js');
|
|
|
148
169
|
var removedGroupId = group.id;
|
|
149
170
|
Logger.info('[TabGroups] Group removed:', removedGroupId);
|
|
150
171
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
var
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
172
|
+
ConnectionManager.forEachConnection(function(entry) {
|
|
173
|
+
var state = entry.state;
|
|
174
|
+
var wsManager = entry.wsManager;
|
|
175
|
+
var clients = state.getCDPClients() || [];
|
|
176
|
+
for (var i = 0; i < clients.length; i++) {
|
|
177
|
+
var clientId = clients[i].id;
|
|
178
|
+
if (state.getGroupIdForClient(clientId) === removedGroupId) {
|
|
179
|
+
Logger.info('[TabGroups] Clearing cached groupId for client:', clientId);
|
|
180
|
+
state.setGroupIdForClient(clientId, null);
|
|
181
|
+
|
|
182
|
+
var attached = state.getAttachedTabIds();
|
|
183
|
+
attached.forEach(function(tid) {
|
|
184
|
+
if (state.getClientIdByTabId(tid) === clientId && !state.isPreExistingTab(tid)) {
|
|
185
|
+
Logger.info('[TabGroups] Re-grouping tab', tid, 'for client:', clientId);
|
|
186
|
+
var ctx = { _state: state, _wsManager: wsManager, clientId: clientId };
|
|
187
|
+
SpecialHandler.addTabToAutomationGroup(tid, clientId, null, ctx);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
166
192
|
}
|
|
167
|
-
}
|
|
193
|
+
});
|
|
168
194
|
});
|
|
169
195
|
}
|
|
170
196
|
|
|
171
197
|
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
|
172
|
-
if (changeInfo.status === 'complete'
|
|
173
|
-
|
|
198
|
+
if (changeInfo.status === 'complete') {
|
|
199
|
+
var entry = ConnectionManager.getConnectionByTabId(tabId);
|
|
200
|
+
if (entry && entry.state.isTabAttached(tabId)) {
|
|
201
|
+
}
|
|
174
202
|
}
|
|
175
203
|
|
|
176
204
|
if (changeInfo.groupId !== undefined && changeInfo.groupId === -1) {
|
|
177
|
-
|
|
178
|
-
|
|
205
|
+
var entry = ConnectionManager.getConnectionByTabId(tabId);
|
|
206
|
+
if (entry && entry.state.isTabAttached(tabId) && !entry.state.isPreExistingTab(tabId)) {
|
|
207
|
+
var state = entry.state;
|
|
208
|
+
var wsManager = entry.wsManager;
|
|
209
|
+
var clientId = state.getClientIdByTabId(tabId);
|
|
179
210
|
if (clientId) {
|
|
180
|
-
var cachedGroupId =
|
|
211
|
+
var cachedGroupId = state.getGroupIdForClient(clientId);
|
|
181
212
|
if (cachedGroupId) {
|
|
182
213
|
Logger.info('[Tabs] Tab', tabId, 'left group, re-adding to cached group:', cachedGroupId);
|
|
183
214
|
chrome.tabs.group({ tabIds: tabId, groupId: cachedGroupId }, function() {
|
|
184
215
|
if (chrome.runtime.lastError) {
|
|
185
216
|
Logger.warn('[Tabs] Failed to re-add tab to group:', chrome.runtime.lastError.message);
|
|
186
|
-
|
|
217
|
+
var ctx = { _state: state, _wsManager: wsManager, clientId: clientId };
|
|
218
|
+
SpecialHandler.addTabToAutomationGroup(tabId, clientId, null, ctx);
|
|
187
219
|
}
|
|
188
220
|
});
|
|
189
221
|
} else {
|
|
190
222
|
Logger.info('[Tabs] Tab', tabId, 'left group, no cached groupId — delegating to addTabToAutomationGroup');
|
|
191
|
-
|
|
223
|
+
var ctx = { _state: state, _wsManager: wsManager, clientId: clientId };
|
|
224
|
+
SpecialHandler.addTabToAutomationGroup(tabId, clientId, null, ctx);
|
|
192
225
|
}
|
|
193
226
|
}
|
|
194
227
|
}
|
|
@@ -197,75 +230,83 @@ importScripts('features/automation-badge.js');
|
|
|
197
230
|
|
|
198
231
|
chrome.tabs.onCreated.addListener(function(tab) {
|
|
199
232
|
Logger.info('[Tabs] Tab created:', tab.id, tab.url, 'openerTabId:', tab.openerTabId);
|
|
200
|
-
|
|
201
|
-
|
|
233
|
+
|
|
234
|
+
var entry = ConnectionManager.getPrimaryConnection();
|
|
235
|
+
if (!entry) return;
|
|
236
|
+
var state = entry.state;
|
|
237
|
+
var wsManager = entry.wsManager;
|
|
238
|
+
|
|
239
|
+
if (!state.hasConnectedClient()) {
|
|
202
240
|
Logger.info('[Tabs] No connected client, skipping');
|
|
203
241
|
return;
|
|
204
242
|
}
|
|
205
|
-
|
|
243
|
+
|
|
206
244
|
var tabId = tab.id;
|
|
207
|
-
|
|
245
|
+
|
|
208
246
|
var tabUrl = tab.url || tab.pendingUrl || 'about:blank';
|
|
209
|
-
if (
|
|
247
|
+
if (state.hasPendingCreatedTabUrl(tabUrl)) {
|
|
210
248
|
Logger.info('[Tabs] Tab created by Target.createTarget, will be handled by createTarget:', tabUrl);
|
|
211
|
-
|
|
249
|
+
state.removePendingCreatedTabUrl(tabUrl);
|
|
212
250
|
return;
|
|
213
251
|
}
|
|
214
|
-
|
|
252
|
+
|
|
215
253
|
var openerTabId = tab.openerTabId;
|
|
216
|
-
var
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
254
|
+
var openerEntry = openerTabId ? ConnectionManager.getConnectionByTabId(openerTabId) : null;
|
|
255
|
+
if (openerEntry) {
|
|
256
|
+
state = openerEntry.state;
|
|
257
|
+
wsManager = openerEntry.wsManager;
|
|
258
|
+
}
|
|
259
|
+
var isOpenerControlled = openerTabId && state.isTabAttached(openerTabId) && !state.isPreExistingTab(openerTabId);
|
|
260
|
+
|
|
220
261
|
if (!openerTabId) {
|
|
221
262
|
Logger.info('[Tabs] Tab has no opener, skipping. tabId:', tabId);
|
|
222
263
|
return;
|
|
223
264
|
}
|
|
224
|
-
|
|
265
|
+
|
|
225
266
|
if (!isOpenerControlled) {
|
|
226
267
|
Logger.info('[Tabs] Opener not controlled by CDP, skipping. tabId:', tabId, 'openerTabId:', openerTabId);
|
|
227
268
|
return;
|
|
228
269
|
}
|
|
229
|
-
|
|
270
|
+
|
|
230
271
|
Logger.info('[Tabs] Tab has controlled opener, will attach. tabId:', tabId, 'openerTabId:', openerTabId);
|
|
231
|
-
|
|
272
|
+
|
|
232
273
|
LocalHandler.getTargetInfoById(String(tabId)).then(function(targetInfo) {
|
|
233
274
|
Logger.info('[Tabs] getTargetInfoById result:', targetInfo ? targetInfo.targetId : 'null');
|
|
234
275
|
if (!targetInfo) {
|
|
235
276
|
Logger.error('[Tabs] getTargetInfoById returned null for tabId:', tabId);
|
|
236
277
|
return;
|
|
237
278
|
}
|
|
238
|
-
|
|
279
|
+
|
|
239
280
|
var targetId = targetInfo.targetId;
|
|
240
281
|
Logger.info('[Tabs] targetId:', targetId);
|
|
241
|
-
|
|
242
|
-
if (
|
|
282
|
+
|
|
283
|
+
if (state.hasEmittedTarget(targetId)) {
|
|
243
284
|
Logger.info('[Tabs] Target already emitted, skipping:', targetId);
|
|
244
285
|
return;
|
|
245
286
|
}
|
|
246
|
-
|
|
247
|
-
|
|
287
|
+
|
|
288
|
+
state.addEmittedTarget(targetId);
|
|
248
289
|
Logger.info('[Tabs] Sending Target.targetCreated event');
|
|
249
|
-
|
|
250
|
-
EventBuilder.send('Target.targetCreated', { targetInfo: targetInfo });
|
|
290
|
+
|
|
291
|
+
EventBuilder.send('Target.targetCreated', { targetInfo: targetInfo }, null, wsManager);
|
|
251
292
|
Logger.info('[Tabs] Target.targetCreated sent, now attaching to tab:', tabId);
|
|
252
|
-
|
|
253
|
-
return DebuggerManager.attach(tabId).then(function(attached) {
|
|
293
|
+
|
|
294
|
+
return DebuggerManager.attach(tabId, state).then(function(attached) {
|
|
254
295
|
Logger.info('[Tabs] DebuggerManager.attach result:', attached);
|
|
255
296
|
if (!attached) {
|
|
256
297
|
Logger.error('[Tabs] Failed to attach to tab:', tabId);
|
|
257
298
|
return;
|
|
258
299
|
}
|
|
259
|
-
|
|
300
|
+
|
|
260
301
|
var sessionId = CDPUtils.generateSessionId();
|
|
261
|
-
|
|
302
|
+
state.mapSession(sessionId, tabId, targetId);
|
|
262
303
|
|
|
263
|
-
var openerClientId = openerTabId ?
|
|
304
|
+
var openerClientId = openerTabId ? state.getClientIdByTabId(openerTabId) : null;
|
|
264
305
|
if (openerClientId) {
|
|
265
|
-
|
|
306
|
+
state.setTabIdToClientId(tabId, openerClientId);
|
|
266
307
|
Logger.info('[Tabs] Mapped child tab', tabId, '-> clientId:', openerClientId);
|
|
267
308
|
}
|
|
268
|
-
|
|
309
|
+
|
|
269
310
|
Config.getAutoMute(function(enabled) {
|
|
270
311
|
if (enabled) {
|
|
271
312
|
chrome.tabs.update(tabId, { muted: true }, function() {
|
|
@@ -277,16 +318,17 @@ importScripts('features/automation-badge.js');
|
|
|
277
318
|
});
|
|
278
319
|
}
|
|
279
320
|
});
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
321
|
+
|
|
322
|
+
var ctx = { _state: state, _wsManager: wsManager, clientId: openerClientId };
|
|
323
|
+
SpecialHandler.addTabToAutomationGroup(tabId, openerClientId, null, ctx);
|
|
324
|
+
|
|
283
325
|
Logger.info('[Tabs] Sending Target.attachedToTarget event');
|
|
284
|
-
|
|
326
|
+
|
|
285
327
|
EventBuilder.send('Target.attachedToTarget', {
|
|
286
328
|
sessionId: sessionId,
|
|
287
329
|
targetInfo: targetInfo,
|
|
288
330
|
waitingForDebugger: false
|
|
289
|
-
});
|
|
331
|
+
}, null, wsManager);
|
|
290
332
|
Logger.info('[Tabs] Target.attachedToTarget sent');
|
|
291
333
|
}).catch(function(err) {
|
|
292
334
|
Logger.error('[Tabs] DebuggerManager.attach error:', err);
|
|
@@ -299,7 +341,7 @@ importScripts('features/automation-badge.js');
|
|
|
299
341
|
chrome.runtime.onInstalled.addListener(function(details) {
|
|
300
342
|
Logger.info('[Runtime] Extension installed/updated:', details.reason);
|
|
301
343
|
State.persist(null, false);
|
|
302
|
-
|
|
344
|
+
setBadgeStatus('ON');
|
|
303
345
|
init();
|
|
304
346
|
});
|
|
305
347
|
|
|
@@ -308,58 +350,67 @@ importScripts('features/automation-badge.js');
|
|
|
308
350
|
init();
|
|
309
351
|
});
|
|
310
352
|
|
|
353
|
+
function broadcastConnectionsUpdated() {
|
|
354
|
+
chrome.runtime.sendMessage({ type: 'connections-updated' }).catch(function() {});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function _getAggregatedState() {
|
|
358
|
+
var isConnected = false;
|
|
359
|
+
var cdpClients = [];
|
|
360
|
+
var attachedTabIds = [];
|
|
361
|
+
ConnectionManager.forEachConnection(function(entry) {
|
|
362
|
+
var ws = entry.state.getWs();
|
|
363
|
+
if (ws && ws.readyState === WebSocket.OPEN) isConnected = true;
|
|
364
|
+
cdpClients = cdpClients.concat(entry.state.getCDPClients() || []);
|
|
365
|
+
attachedTabIds = attachedTabIds.concat(entry.state.getAttachedTabIds());
|
|
366
|
+
});
|
|
367
|
+
return { isConnected: isConnected, cdpClients: cdpClients, attachedTabIds: attachedTabIds };
|
|
368
|
+
}
|
|
369
|
+
|
|
311
370
|
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
|
312
371
|
if (message.type === 'popup-query') {
|
|
313
|
-
var
|
|
314
|
-
var isConnected = ws && ws.readyState === WebSocket.OPEN;
|
|
372
|
+
var agg = _getAggregatedState();
|
|
315
373
|
chrome.storage.local.get(['wsAddress', 'pluginId'], function(result) {
|
|
316
374
|
sendResponse({
|
|
317
|
-
connected: isConnected,
|
|
375
|
+
connected: agg.isConnected,
|
|
318
376
|
pluginId: result.pluginId || null,
|
|
319
|
-
cdpClients:
|
|
320
|
-
attachedPages:
|
|
377
|
+
cdpClients: agg.cdpClients,
|
|
378
|
+
attachedPages: agg.attachedTabIds.map(function(tid) { return { tabId: tid }; })
|
|
321
379
|
});
|
|
322
380
|
});
|
|
323
381
|
return true;
|
|
324
382
|
} else if (message.type === 'ws-reconnect') {
|
|
325
383
|
Logger.info('[Runtime] WS address changed, reconnecting');
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
WebSocketManager.connect();
|
|
384
|
+
ConnectionManager.disconnectAll();
|
|
385
|
+
ConnectionManager.connectAll();
|
|
329
386
|
sendResponse({ success: true });
|
|
330
387
|
} else if (message.type === 'reconnect') {
|
|
331
388
|
Logger.info('[Runtime] Received reconnect request from popup');
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
ws.close();
|
|
335
|
-
}
|
|
336
|
-
WebSocketManager.connect();
|
|
389
|
+
ConnectionManager.disconnectAll();
|
|
390
|
+
ConnectionManager.connectAll();
|
|
337
391
|
sendResponse({ success: true });
|
|
338
392
|
} else if (message.type === 'getState') {
|
|
339
|
-
var
|
|
340
|
-
var isConnected = ws && ws.readyState === WebSocket.OPEN;
|
|
341
|
-
|
|
393
|
+
var agg = _getAggregatedState();
|
|
342
394
|
chrome.storage.local.get(['wsAddress'], function(result) {
|
|
343
|
-
var attachedTabs =
|
|
344
|
-
|
|
345
|
-
|
|
395
|
+
var attachedTabs = agg.attachedTabIds;
|
|
396
|
+
|
|
346
397
|
if (attachedTabs.length === 0) {
|
|
347
398
|
sendResponse({
|
|
348
|
-
connected: isConnected,
|
|
399
|
+
connected: agg.isConnected,
|
|
349
400
|
serverAddress: result.wsAddress || Config.WS_URL,
|
|
350
|
-
cdpClients: cdpClients,
|
|
401
|
+
cdpClients: agg.cdpClients,
|
|
351
402
|
attachedPages: []
|
|
352
403
|
});
|
|
353
404
|
return;
|
|
354
405
|
}
|
|
355
|
-
|
|
406
|
+
|
|
356
407
|
var attachedPages = [];
|
|
357
408
|
var pendingTabs = attachedTabs.length;
|
|
358
|
-
|
|
409
|
+
|
|
359
410
|
attachedTabs.forEach(function(tabId) {
|
|
360
411
|
chrome.tabs.get(tabId, function(tab) {
|
|
361
412
|
pendingTabs--;
|
|
362
|
-
|
|
413
|
+
|
|
363
414
|
if (chrome.runtime.lastError) {
|
|
364
415
|
Logger.info('[Runtime] Tab not found:', tabId);
|
|
365
416
|
} else if (tab) {
|
|
@@ -369,30 +420,27 @@ importScripts('features/automation-badge.js');
|
|
|
369
420
|
url: tab.url || ''
|
|
370
421
|
});
|
|
371
422
|
}
|
|
372
|
-
|
|
423
|
+
|
|
373
424
|
if (pendingTabs === 0) {
|
|
374
425
|
sendResponse({
|
|
375
|
-
connected: isConnected,
|
|
426
|
+
connected: agg.isConnected,
|
|
376
427
|
serverAddress: result.wsAddress || Config.WS_URL,
|
|
377
|
-
cdpClients: cdpClients,
|
|
428
|
+
cdpClients: agg.cdpClients,
|
|
378
429
|
attachedPages: attachedPages
|
|
379
430
|
});
|
|
380
431
|
}
|
|
381
432
|
});
|
|
382
433
|
});
|
|
383
434
|
});
|
|
384
|
-
|
|
435
|
+
|
|
385
436
|
return true;
|
|
386
437
|
} else if (message.type === 'connect') {
|
|
387
438
|
var address = message.serverAddress;
|
|
388
439
|
if (address) {
|
|
389
440
|
Logger.info('[Runtime] Saving and connecting to:', address);
|
|
390
441
|
chrome.storage.local.set({ wsAddress: address }, function() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
ws.close();
|
|
394
|
-
}
|
|
395
|
-
WebSocketManager.connect();
|
|
442
|
+
ConnectionManager.disconnectAll();
|
|
443
|
+
ConnectionManager.connectAll();
|
|
396
444
|
sendResponse({ success: true });
|
|
397
445
|
});
|
|
398
446
|
} else {
|
|
@@ -401,23 +449,79 @@ importScripts('features/automation-badge.js');
|
|
|
401
449
|
return true;
|
|
402
450
|
} else if (message.type === 'disconnect') {
|
|
403
451
|
Logger.info('[Runtime] Disconnecting...');
|
|
404
|
-
|
|
405
|
-
if (ws) {
|
|
406
|
-
ws.close();
|
|
407
|
-
}
|
|
452
|
+
ConnectionManager.disconnectAll();
|
|
408
453
|
sendResponse({ success: true });
|
|
454
|
+
} else if (message.type === 'get-connection-statuses') {
|
|
455
|
+
Config.getConnections(function(connections) {
|
|
456
|
+
var statuses = {};
|
|
457
|
+
(connections || []).forEach(function(conn) {
|
|
458
|
+
if (!conn.enabled) {
|
|
459
|
+
statuses[conn.id] = 'disabled';
|
|
460
|
+
} else {
|
|
461
|
+
var entry = ConnectionManager.getConnection(conn.id);
|
|
462
|
+
if (entry) {
|
|
463
|
+
var ws = entry.state.getWs();
|
|
464
|
+
statuses[conn.id] = (ws && ws.readyState === WebSocket.OPEN) ? 'connected' : 'error';
|
|
465
|
+
} else {
|
|
466
|
+
statuses[conn.id] = 'error';
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
sendResponse({ statuses: statuses });
|
|
471
|
+
});
|
|
472
|
+
return true;
|
|
473
|
+
} else if (message.type === 'add-connection') {
|
|
474
|
+
Logger.info('[Runtime] Adding connection:', message.tag, message.url);
|
|
475
|
+
Config.addConnection({ tag: message.tag, url: message.url }, function(conn) {
|
|
476
|
+
if (conn && conn.enabled) {
|
|
477
|
+
ConnectionManager.addConnection(conn);
|
|
478
|
+
var entry = ConnectionManager.getConnection(conn.id);
|
|
479
|
+
if (entry) entry.wsManager.connect();
|
|
480
|
+
}
|
|
481
|
+
broadcastConnectionsUpdated();
|
|
482
|
+
sendResponse({ success: true });
|
|
483
|
+
});
|
|
484
|
+
return true;
|
|
485
|
+
} else if (message.type === 'remove-connection') {
|
|
486
|
+
Logger.info('[Runtime] Removing connection:', message.connectionId);
|
|
487
|
+
ConnectionManager.removeConnection(message.connectionId);
|
|
488
|
+
Config.removeConnection(message.connectionId, function() {
|
|
489
|
+
broadcastConnectionsUpdated();
|
|
490
|
+
sendResponse({ success: true });
|
|
491
|
+
});
|
|
492
|
+
return true;
|
|
493
|
+
} else if (message.type === 'toggle-connection') {
|
|
494
|
+
Logger.info('[Runtime] Toggling connection:', message.connectionId, message.enabled);
|
|
495
|
+
Config.toggleConnection(message.connectionId, message.enabled, function() {
|
|
496
|
+
if (message.enabled) {
|
|
497
|
+
Config.getConnections(function(connections) {
|
|
498
|
+
var conn = (connections || []).find(function(c) { return c.id === message.connectionId; });
|
|
499
|
+
if (conn) {
|
|
500
|
+
var wsMgr = ConnectionManager.addConnection(conn);
|
|
501
|
+
if (wsMgr) wsMgr.connect();
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
} else {
|
|
505
|
+
ConnectionManager.removeConnection(message.connectionId);
|
|
506
|
+
}
|
|
507
|
+
broadcastConnectionsUpdated();
|
|
508
|
+
sendResponse({ success: true });
|
|
509
|
+
});
|
|
510
|
+
return true;
|
|
409
511
|
}
|
|
410
512
|
return true;
|
|
411
513
|
});
|
|
412
514
|
|
|
413
515
|
chrome.alarms.onAlarm.addListener(function(alarm) {
|
|
414
516
|
if (alarm.name === 'sw-keepalive') {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
517
|
+
ConnectionManager.forEachConnection(function(entry) {
|
|
518
|
+
var ws = entry.state.getWs();
|
|
519
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
520
|
+
entry.wsManager.send({ type: 'keepalive', timestamp: Date.now() });
|
|
521
|
+
} else {
|
|
522
|
+
entry.wsManager.connect();
|
|
523
|
+
}
|
|
524
|
+
});
|
|
421
525
|
}
|
|
422
526
|
});
|
|
423
527
|
|
|
@@ -4,15 +4,16 @@ var ForwardHandler = (function() {
|
|
|
4
4
|
var method = context.method;
|
|
5
5
|
var params = context.params;
|
|
6
6
|
var sessionId = context.sessionId;
|
|
7
|
+
var state = context._state;
|
|
7
8
|
|
|
8
|
-
var tabId = resolveTabId(sessionId);
|
|
9
|
+
var tabId = resolveTabId(sessionId, state);
|
|
9
10
|
|
|
10
11
|
if (!tabId) {
|
|
11
12
|
Logger.warn('[Forward] No tabId for command:', method);
|
|
12
13
|
return Promise.reject({ code: -32000, message: 'No target found for command: ' + method });
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
if (!
|
|
16
|
+
if (!state.isTabAttached(tabId)) {
|
|
16
17
|
Logger.warn('[Forward] Tab not attached, skipping command:', method, 'tabId:', tabId);
|
|
17
18
|
return Promise.reject({ code: -32000, message: 'Target is not attached' });
|
|
18
19
|
}
|
|
@@ -23,15 +24,16 @@ var ForwardHandler = (function() {
|
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
function resolveTabId(sessionId) {
|
|
27
|
+
function resolveTabId(sessionId, state) {
|
|
28
|
+
if (!state) return null;
|
|
27
29
|
if (sessionId) {
|
|
28
|
-
return
|
|
30
|
+
return state.getTabIdBySession(sessionId);
|
|
29
31
|
}
|
|
30
|
-
var currentTabId =
|
|
31
|
-
if (currentTabId != null &&
|
|
32
|
+
var currentTabId = state.getCurrentTabId();
|
|
33
|
+
if (currentTabId != null && state.isTabAttached(currentTabId)) {
|
|
32
34
|
return currentTabId;
|
|
33
35
|
}
|
|
34
|
-
var attachedTabs =
|
|
36
|
+
var attachedTabs = state.getAttachedTabIds();
|
|
35
37
|
if (attachedTabs.length > 0) {
|
|
36
38
|
return attachedTabs[0];
|
|
37
39
|
}
|