@@ -80,7 +80,39 @@ enum Trigger {
80
80
extensionIcon,
81
81
}
82
82
83
- void attachDebugger (int dartAppTabId, {required Trigger trigger}) {
83
+ enum DebuggerLocation {
84
+ angularDartDevTools,
85
+ chromeDevTools,
86
+ dartDevTools,
87
+ ide;
88
+
89
+ String get displayName {
90
+ switch (this ) {
91
+ case DebuggerLocation .angularDartDevTools:
92
+ return 'AngularDart DevTools' ;
93
+ case DebuggerLocation .chromeDevTools:
94
+ return 'Chrome DevTools' ;
95
+ case DebuggerLocation .dartDevTools:
96
+ return 'a Dart DevTools tab' ;
97
+ case DebuggerLocation .ide:
98
+ return 'an IDE' ;
99
+ }
100
+ }
101
+ }
102
+
103
+ void attachDebugger (int dartAppTabId, {required Trigger trigger}) async {
104
+ // Check if a debugger is already attached:
105
+ final existingDebuggerLocation = _debuggerLocation (dartAppTabId);
106
+ if (existingDebuggerLocation != null ) {
107
+ return _showWarningNotification (
108
+ 'Already debugging in ${existingDebuggerLocation .displayName }.' ,
109
+ );
110
+ }
111
+
112
+ // Verify that the user is authenticated:
113
+ final isAuthenticated = await _authenticateUser (dartAppTabId);
114
+ if (! isAuthenticated) return ;
115
+
84
116
_tabIdToTrigger[dartAppTabId] = trigger;
85
117
_registerDebugEventListeners ();
86
118
chrome.debugger.attach (
@@ -154,11 +186,15 @@ String _translateChromeError(String chromeErrorMessage) {
154
186
155
187
Future <void > _onDebuggerEvent (
156
188
Debuggee source, String method, Object ? params) async {
189
+ final tabId = source.tabId;
157
190
maybeForwardMessageToAngularDartDevTools (
158
191
method: method, params: params, tabId: source.tabId);
159
192
160
193
if (method == 'Runtime.executionContextCreated' ) {
161
- return _maybeConnectToDwds (source.tabId, params);
194
+ // Only try to connect to DWDS if we don't already have a debugger instance:
195
+ if (_debuggerLocation (tabId) == null ) {
196
+ return _maybeConnectToDwds (source.tabId, params);
197
+ }
162
198
}
163
199
164
200
return _forwardChromeDebuggerEventToDwds (source, method, params);
@@ -183,7 +219,7 @@ Future<void> _maybeConnectToDwds(int tabId, Object? params) async {
183
219
);
184
220
if (! connected) {
185
221
debugWarn ('Failed to connect to DWDS for $contextOrigin .' );
186
- sendConnectFailureMessage (ConnectFailureReason .unknown,
222
+ _sendConnectFailureMessage (ConnectFailureReason .unknown,
187
223
dartAppTabId: tabId);
188
224
}
189
225
}
@@ -373,7 +409,7 @@ void _removeDebugSession(_DebugSession debugSession) {
373
409
}
374
410
}
375
411
376
- void sendConnectFailureMessage (ConnectFailureReason reason,
412
+ void _sendConnectFailureMessage (ConnectFailureReason reason,
377
413
{required int dartAppTabId}) async {
378
414
final json = jsonEncode (serializers.serialize (ConnectFailure ((b) => b
379
415
..tabId = dartAppTabId
@@ -409,6 +445,81 @@ _DebugSession? _debugSessionForTab(tabId, {required TabType type}) {
409
445
}
410
446
}
411
447
448
+ Future <bool > _authenticateUser (int tabId) async {
449
+ final isAlreadyAuthenticated = await _fetchIsAuthenticated (tabId);
450
+ if (isAlreadyAuthenticated) return true ;
451
+ final debugInfo = await fetchStorageObject <DebugInfo >(
452
+ type: StorageObject .debugInfo,
453
+ tabId: tabId,
454
+ );
455
+ final authUrl = debugInfo? .authUrl;
456
+ if (authUrl == null ) {
457
+ _showWarningNotification ('Cannot authenticate user.' );
458
+ return false ;
459
+ }
460
+ final isAuthenticated = await _sendAuthRequest (authUrl);
461
+ if (isAuthenticated) {
462
+ await setStorageObject <String >(
463
+ type: StorageObject .isAuthenticated,
464
+ value: '$isAuthenticated ' ,
465
+ tabId: tabId,
466
+ );
467
+ } else {
468
+ _sendConnectFailureMessage (
469
+ ConnectFailureReason .authentication,
470
+ dartAppTabId: tabId,
471
+ );
472
+ await createTab (authUrl, inNewWindow: false );
473
+ }
474
+ return isAuthenticated;
475
+ }
476
+
477
+ Future <bool > _fetchIsAuthenticated (int tabId) async {
478
+ final authenticated = await fetchStorageObject <String >(
479
+ type: StorageObject .isAuthenticated,
480
+ tabId: tabId,
481
+ );
482
+ return authenticated == 'true' ;
483
+ }
484
+
485
+ Future <bool > _sendAuthRequest (String authUrl) async {
486
+ final response = await fetchRequest (authUrl);
487
+ final responseBody = response.body ?? '' ;
488
+ return responseBody.contains ('Dart Debug Authentication Success!' );
489
+ }
490
+
491
+ void _showWarningNotification (String message) {
492
+ chrome.notifications.create (
493
+ /*notificationId*/ null ,
494
+ NotificationOptions (
495
+ title: '[Error] Dart Debug Extension' ,
496
+ message: message,
497
+ iconUrl: 'static_assets/dart.png' ,
498
+ type: 'basic' ,
499
+ ),
500
+ /*callback*/ null ,
501
+ );
502
+ }
503
+
504
+ DebuggerLocation ? _debuggerLocation (int dartAppTabId) {
505
+ final debugSession = _debugSessionForTab (dartAppTabId, type: TabType .dartApp);
506
+ final trigger = _tabIdToTrigger[dartAppTabId];
507
+ if (debugSession == null || trigger == null ) return null ;
508
+
509
+ switch (trigger) {
510
+ case Trigger .extensionIcon:
511
+ if (debugSession.devToolsTabId != null ) {
512
+ return DebuggerLocation .dartDevTools;
513
+ } else {
514
+ return DebuggerLocation .ide;
515
+ }
516
+ case Trigger .angularDartDevTools:
517
+ return DebuggerLocation .angularDartDevTools;
518
+ case Trigger .extensionPanel:
519
+ return DebuggerLocation .chromeDevTools;
520
+ }
521
+ }
522
+
412
523
/// Construct an [ExtensionEvent] from [method] and [params] .
413
524
ExtensionEvent _extensionEventFor (String method, dynamic params) {
414
525
return ExtensionEvent ((b) => b
0 commit comments