@@ -49,6 +49,7 @@ enum DetachReason {
4949 connectionDoneEvent,
5050 devToolsTabClosed,
5151 navigatedAwayFromApp,
52+ staleDebugSession,
5253 unknown;
5354
5455 factory DetachReason .fromString (String value) {
@@ -127,40 +128,60 @@ void attachDebugger(int dartAppTabId, {required Trigger trigger}) async {
127128 );
128129}
129130
130- void detachDebugger (
131+ Future < bool > detachDebugger (
131132 int tabId, {
132133 required TabType type,
133134 required DetachReason reason,
134135}) async {
135136 final debugSession = _debugSessionForTab (tabId, type: type);
136- if (debugSession == null ) return ;
137+ if (debugSession == null ) return false ;
137138 final debuggee = Debuggee (tabId: debugSession.appTabId);
139+ final completer = Completer <bool >();
138140 chrome.debugger.detach (debuggee, allowInterop (() {
139141 final error = chrome.runtime.lastError;
140142 if (error != null ) {
141143 debugWarn (
142144 'Error detaching tab for reason: $reason . Error: ${error .message }' );
145+ completer.complete (false );
143146 } else {
144147 _handleDebuggerDetach (debuggee, reason);
148+ completer.complete (true );
145149 }
146150 }));
151+ return completer.future;
152+ }
153+
154+ bool isActiveDebugSession (int tabId) =>
155+ _debugSessionForTab (tabId, type: TabType .dartApp) != null ;
156+
157+ Future <void > clearStaleDebugSession (int tabId) async {
158+ final debugSession = _debugSessionForTab (tabId, type: TabType .dartApp);
159+ if (debugSession != null ) {
160+ await detachDebugger (
161+ tabId,
162+ type: TabType .dartApp,
163+ reason: DetachReason .staleDebugSession,
164+ );
165+ } else {
166+ await _removeDebugSessionDataInStorage (tabId);
167+ }
147168}
148169
149170void _registerDebugEventListeners () {
150171 chrome.debugger.onEvent.addListener (allowInterop (_onDebuggerEvent));
151- chrome.debugger.onDetach.addListener (allowInterop (
152- (source, _) => _handleDebuggerDetach (
172+ chrome.debugger.onDetach.addListener (allowInterop ((source, _) async {
173+ await _handleDebuggerDetach (
153174 source,
154175 DetachReason .canceledByUser,
155- ),
156- ));
157- chrome.tabs.onRemoved.addListener (allowInterop (
158- (tabId, _) => detachDebugger (
176+ );
177+ } ));
178+ chrome.tabs.onRemoved.addListener (allowInterop ((tabId, _) async {
179+ await detachDebugger (
159180 tabId,
160181 type: TabType .devTools,
161182 reason: DetachReason .devToolsTabClosed,
162- ),
163- ));
183+ );
184+ } ));
164185}
165186
166187_enableExecutionContextReporting (int tabId) {
@@ -222,7 +243,7 @@ Future<void> _maybeConnectToDwds(int tabId, Object? params) async {
222243 );
223244 if (! connected) {
224245 debugWarn ('Failed to connect to DWDS for $contextOrigin .' );
225- _sendConnectFailureMessage (ConnectFailureReason .unknown,
246+ await _sendConnectFailureMessage (ConnectFailureReason .unknown,
226247 dartAppTabId: tabId);
227248 }
228249}
@@ -247,16 +268,16 @@ Future<bool> _connectToDwds({
247268 appTabId: dartAppTabId,
248269 trigger: trigger,
249270 onIncoming: (data) => _routeDwdsEvent (data, client, dartAppTabId),
250- onDone: () {
251- detachDebugger (
271+ onDone: () async {
272+ await detachDebugger (
252273 dartAppTabId,
253274 type: TabType .dartApp,
254275 reason: DetachReason .connectionDoneEvent,
255276 );
256277 },
257- onError: (err) {
278+ onError: (err) async {
258279 debugWarn ('Connection error: $err ' , verbose: true );
259- detachDebugger (
280+ await detachDebugger (
260281 dartAppTabId,
261282 type: TabType .dartApp,
262283 reason: DetachReason .connectionErrorEvent,
@@ -377,24 +398,26 @@ void _openDevTools(String devToolsUri, {required int dartAppTabId}) async {
377398 }
378399}
379400
380- void _handleDebuggerDetach (Debuggee source, DetachReason reason) async {
401+ Future < void > _handleDebuggerDetach (Debuggee source, DetachReason reason) async {
381402 final tabId = source.tabId;
382403 debugLog (
383404 'Debugger detached due to: $reason ' ,
384405 verbose: true ,
385406 prefix: '$tabId ' ,
386407 );
387408 final debugSession = _debugSessionForTab (tabId, type: TabType .dartApp);
388- if (debugSession == null ) return ;
389- debugLog ('Removing debug session...' );
390- _removeDebugSession (debugSession);
391- // Notify the extension panels that the debug session has ended:
392- _sendStopDebuggingMessage (reason, dartAppTabId: source.tabId);
393- // Remove the DevTools URI and encoded URI from storage:
394- await removeStorageObject (type: StorageObject .devToolsUri, tabId: tabId);
395- await removeStorageObject (type: StorageObject .encodedUri, tabId: tabId);
396- // Maybe close the associated DevTools tab as well:
397- final devToolsTabId = debugSession.devToolsTabId;
409+ if (debugSession != null ) {
410+ debugLog ('Removing debug session...' );
411+ _removeDebugSession (debugSession);
412+ // Notify the extension panels that the debug session has ended:
413+ await _sendStopDebuggingMessage (reason, dartAppTabId: tabId);
414+ // Maybe close the associated DevTools tab as well:
415+ await _maybeCloseDevTools (debugSession.devToolsTabId);
416+ }
417+ await _removeDebugSessionDataInStorage (tabId);
418+ }
419+
420+ Future <void > _maybeCloseDevTools (int ? devToolsTabId) async {
398421 if (devToolsTabId == null ) return ;
399422 final devToolsTab = await getTab (devToolsTabId);
400423 if (devToolsTab != null ) {
@@ -403,6 +426,12 @@ void _handleDebuggerDetach(Debuggee source, DetachReason reason) async {
403426 }
404427}
405428
429+ Future <void > _removeDebugSessionDataInStorage (int tabId) async {
430+ // Remove the DevTools URI and encoded URI from storage:
431+ await removeStorageObject (type: StorageObject .devToolsUri, tabId: tabId);
432+ await removeStorageObject (type: StorageObject .encodedUri, tabId: tabId);
433+ }
434+
406435void _removeDebugSession (_DebugSession debugSession) {
407436 // Note: package:sse will try to keep the connection alive, even after the
408437 // client has been closed. Therefore the extension sends an event to notify
@@ -422,25 +451,25 @@ void _removeDebugSession(_DebugSession debugSession) {
422451 }
423452}
424453
425- void _sendConnectFailureMessage (ConnectFailureReason reason,
454+ Future < bool > _sendConnectFailureMessage (ConnectFailureReason reason,
426455 {required int dartAppTabId}) async {
427456 final json = jsonEncode (serializers.serialize (ConnectFailure ((b) => b
428457 ..tabId = dartAppTabId
429458 ..reason = reason.name)));
430- sendRuntimeMessage (
459+ return await sendRuntimeMessage (
431460 type: MessageType .connectFailure,
432461 body: json,
433462 sender: Script .background,
434463 recipient: Script .debuggerPanel);
435464}
436465
437- void _sendStopDebuggingMessage (DetachReason reason,
466+ Future < bool > _sendStopDebuggingMessage (DetachReason reason,
438467 {required int dartAppTabId}) async {
439468 final json = jsonEncode (serializers.serialize (DebugStateChange ((b) => b
440469 ..tabId = dartAppTabId
441470 ..reason = reason.name
442471 ..newState = DebugStateChange .stopDebugging)));
443- sendRuntimeMessage (
472+ return await sendRuntimeMessage (
444473 type: MessageType .debugStateChange,
445474 body: json,
446475 sender: Script .background,
@@ -478,7 +507,7 @@ Future<bool> _authenticateUser(int tabId) async {
478507 tabId: tabId,
479508 );
480509 } else {
481- _sendConnectFailureMessage (
510+ await _sendConnectFailureMessage (
482511 ConnectFailureReason .authentication,
483512 dartAppTabId: tabId,
484513 );
@@ -622,8 +651,20 @@ class _DebugSession {
622651 }
623652
624653 void close () {
625- _socketClient.close ();
626- _batchSubscription.cancel ();
627- _batchController.close ();
654+ try {
655+ _socketClient.close ();
656+ } catch (error) {
657+ debugError ('Error closing socket client: $error ' );
658+ }
659+ try {
660+ _batchSubscription.cancel ();
661+ } catch (error) {
662+ debugError ('Error canceling batch subscription: $error ' );
663+ }
664+ try {
665+ _batchController.close ();
666+ } catch (error) {
667+ debugError ('Error closing batch controller: $error ' );
668+ }
628669 }
629670}
0 commit comments