Skip to content

Commit b870d87

Browse files
committed
added NoClientsAvailableException logic
1 parent 2517aa9 commit b870d87

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

dwds/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## 26.1.0-wip
22

3+
- Added `NoClientsAvailableException` and structured error responses with `noClientsAvailable` field for graceful handling when no browser clients are connected during hot reload or hot restart operations.
34
- `pause` now does not send a `PauseInterrupted` event in
45
`WebSocketProxyService` as we didn't actually pause.
56

dwds/lib/src/services/web_socket_proxy_service.dart

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ class _ServiceExtensionTracker {
117117
}
118118
}
119119

120+
/// Exception thrown when no browser clients are connected to DWDS.
121+
class NoClientsAvailableException implements Exception {
122+
final String message;
123+
final String operation;
124+
125+
NoClientsAvailableException(this.message, {required this.operation});
126+
127+
@override
128+
String toString() => 'NoClientsAvailableException: $message';
129+
}
130+
120131
/// WebSocket-based VM service proxy for web debugging.
121132
class WebSocketProxyService extends ProxyService {
122133
final _logger = Logger('WebSocketProxyService');
@@ -504,6 +515,14 @@ class WebSocketProxyService extends ProxyService {
504515
await _performWebSocketHotReload();
505516
_logger.info('Hot reload completed successfully');
506517
return _ReloadReportWithMetadata(success: true);
518+
} on NoClientsAvailableException catch (e) {
519+
// Gracefully handle no clients scenario
520+
_logger.info('No clients available for hot reload');
521+
return _ReloadReportWithMetadata(
522+
success: false,
523+
notices: [e.message],
524+
noClientsAvailable: true,
525+
);
507526
} catch (e) {
508527
_logger.warning('Hot reload failed: $e');
509528
return _ReloadReportWithMetadata(success: false, notices: [e.toString()]);
@@ -518,6 +537,16 @@ class WebSocketProxyService extends ProxyService {
518537
await _performWebSocketHotRestart();
519538
_logger.info('Hot restart completed successfully');
520539
return {'result': vm_service.Success().toJson()};
540+
} on NoClientsAvailableException catch (e) {
541+
// Return structured response indicating no clients available
542+
_logger.info('No clients available for hot restart');
543+
return {
544+
'result': {
545+
'type': 'Success',
546+
'noClientsAvailable': true,
547+
'message': e.message,
548+
},
549+
};
521550
} catch (e) {
522551
_logger.warning('Hot restart failed: $e');
523552
return {
@@ -611,7 +640,11 @@ class WebSocketProxyService extends ProxyService {
611640
});
612641

613642
if (clientCount == 0) {
614-
throw StateError('No clients available for hot reload');
643+
_logger.warning('No clients available for hot reload');
644+
throw NoClientsAvailableException(
645+
'No clients available for hot reload',
646+
operation: 'hot reload',
647+
);
615648
}
616649

617650
// Create tracker for this hot reload request
@@ -671,7 +704,11 @@ class WebSocketProxyService extends ProxyService {
671704
});
672705

673706
if (clientCount == 0) {
674-
throw StateError('No clients available for hot restart');
707+
_logger.warning('No clients available for hot restart');
708+
throw NoClientsAvailableException(
709+
'No clients available for hot restart',
710+
operation: 'hot restart',
711+
);
675712
}
676713

677714
// Create tracker for this hot restart request
@@ -737,9 +774,8 @@ class WebSocketProxyService extends ProxyService {
737774
final request = ServiceExtensionRequest.fromArgs(
738775
id: requestId,
739776
method: method,
740-
args: args != null
741-
? Map<String, dynamic>.from(args)
742-
: <String, dynamic>{},
777+
args:
778+
args != null ? Map<String, dynamic>.from(args) : <String, dynamic>{},
743779
);
744780

745781
// Send the request and get the number of connected clients
@@ -940,8 +976,8 @@ class WebSocketProxyService extends ProxyService {
940976
/// Pauses execution of the isolate.
941977
@override
942978
Future<Success> pause(String isolateId) =>
943-
// Can't pause with the web socket implementation, so do nothing.
944-
Future.value(Success());
979+
// Can't pause with the web socket implementation, so do nothing.
980+
Future.value(Success());
945981

946982
/// Resumes execution of the isolate.
947983
@override
@@ -1049,13 +1085,20 @@ class WebSocketProxyService extends ProxyService {
10491085
/// Extended ReloadReport that includes additional metadata in JSON output.
10501086
class _ReloadReportWithMetadata extends vm_service.ReloadReport {
10511087
final List<String>? notices;
1052-
_ReloadReportWithMetadata({super.success, this.notices});
1088+
final bool noClientsAvailable;
1089+
1090+
_ReloadReportWithMetadata({
1091+
super.success,
1092+
this.notices,
1093+
this.noClientsAvailable = false,
1094+
});
10531095

10541096
@override
10551097
Map<String, dynamic> toJson() {
10561098
final jsonified = <String, Object?>{
10571099
'type': 'ReloadReport',
10581100
'success': success ?? false,
1101+
'noClientsAvailable': noClientsAvailable,
10591102
};
10601103
if (notices != null) {
10611104
jsonified['notices'] = notices!.map((e) => {'message': e}).toList();

0 commit comments

Comments
 (0)