Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ class NetworkController extends DevToolsScreenController
..updateOrAddAll(
requests: httpProfileData,
sockets: socketStatsData,
webSockets: const [],
timelineMicrosOffset: offlineData.timelineMicrosOffset ?? 0,
);
_filterAndRefreshSearchMatches();
Expand All @@ -265,12 +266,14 @@ class NetworkController extends DevToolsScreenController
void processNetworkTrafficHelper(
List<SocketStatistic> sockets,
List<HttpProfileRequest>? httpRequests,
List<WebSocketConnection> webSockets,
int timelineMicrosOffset, {
required CurrentNetworkRequests currentRequests,
}) {
currentRequests.updateOrAddAll(
requests: httpRequests!,
sockets: sockets,
webSockets: webSockets,
timelineMicrosOffset: timelineMicrosOffset,
);

Expand All @@ -287,11 +290,13 @@ class NetworkController extends DevToolsScreenController
void processNetworkTraffic({
required List<SocketStatistic> sockets,
required List<HttpProfileRequest>? httpRequests,
required List<WebSocketConnection> webSockets,
}) {
// Trigger refresh.
processNetworkTrafficHelper(
sockets,
httpRequests,
webSockets,
_timelineMicrosOffset,
currentRequests: _currentNetworkRequests,
);
Expand Down Expand Up @@ -339,6 +344,9 @@ class NetworkController extends DevToolsScreenController
await networkService.updateLastHttpDataRefreshTime(
alreadyRecordingHttp: alreadyRecordingHttp,
);
networkService.updateLastWebSocketDataRefreshTime(
alreadyRecordingWebSocket: alreadyRecordingHttp,
);
final timestamp = await networkService.updateLastSocketDataRefreshTime(
alreadyRecordingSocketData: alreadyRecordingSocketData,
);
Expand Down Expand Up @@ -391,10 +399,11 @@ class NetworkController extends DevToolsScreenController
_recordingNotifier.value = state;
}

/// Updates the last refresh time of the socket and http data refresh times.
/// Updates the last refresh time of the HTTP, WebSocket, and Socket data.
///
/// This will ensure that future fetches for http and socket requests will at
/// most fetch requests since [updateLastRefreshTime] was called.
/// This will ensure that future fetches for http, socket and websocket
/// requests will atmost fetch requests since [updateLastRefreshTime] was
/// called.
Future<void> updateLastRefreshTime() async {
await networkService.updateLastHttpDataRefreshTime();
await networkService.updateLastSocketDataRefreshTime();
Expand Down Expand Up @@ -571,10 +580,12 @@ class CurrentNetworkRequests extends ValueNotifier<List<NetworkRequest>> {
void updateOrAddAll({
required List<HttpProfileRequest> requests,
required List<SocketStatistic> sockets,
required List<WebSocketConnection> webSockets,
required int timelineMicrosOffset,
}) {
_updateOrAddRequests(requests);
_updateSocketProfiles(sockets, timelineMicrosOffset);
_updateWebSocketProfiles(webSockets);
notifyListeners();
}

Expand Down Expand Up @@ -631,6 +642,20 @@ class CurrentNetworkRequests extends ValueNotifier<List<NetworkRequest>> {
}
}

void _updateWebSocketProfiles(List<WebSocketConnection> webSockets) {
for (final connection in webSockets) {
final webSocket = WebSocket(connection);
final existingRequest = _requestsById[webSocket.id];

if (existingRequest == null) {
_requestsById[webSocket.id] = webSocket;
value.add(webSocket);
} else {
(existingRequest as WebSocket).update(webSocket);
}
}
}

void clear({bool partial = false}) {
if (partial) {
_requestsById.keys
Expand Down
116 changes: 116 additions & 0 deletions packages/devtools_app/lib/src/screens/network/network_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,119 @@ extension SocketExtension on List<Socket> {
return map((socket) => socket._socket).toList();
}
}

class WebSocket extends NetworkRequest {
WebSocket(this._connection);

WebSocketConnection _connection;
WebSocketConnection get connection => _connection;
List<WebSocketEvent> get events => _connection.events;

String get connectionId => _connection.id;
String? get protocol => _connection.protocol;
String get state => _connection.state;

DateTime get lastUpdated => _connection.lastUpdated;

int get bytesSent => _connection.bytesSent;
int get bytesReceived => _connection.bytesReceived;
int get framesSent => _connection.framesSent;
int get framesReceived => _connection.framesReceived;
int get pingCount => _connection.pingCount;
int get pongCount => _connection.pongCount;
int? get closeCode => _connection.closeCode;
String? get closeReason => _connection.closeReason;
String? get error => _connection.error;

void update(WebSocket other) {
_connection = other._connection;
notifyListeners();
}

@override
String get id => 'websocket:${_connection.isolateId}:${_connection.id}';

@override
String get method => 'WEBSOCKET';

@override
String get uri => _connection.uri.toString();

@override
String? get contentType => 'websocket';

@override
String get type => 'WebSocket';

@override
Duration? get duration =>
_connection.closeTimestamp?.difference(_connection.connectTimestamp);

@override
DateTime get startTimestamp => _connection.connectTimestamp;

@override
DateTime? get endTimestamp => _connection.closeTimestamp;

@override
String get status => _connection.state;

@override
int? get port => _connection.uri.hasPort ? _connection.uri.port : null;

@override
int get requestBytes => _connection.bytesSent;

@override
int get responseBytes => _connection.bytesReceived;

@override
bool get didFail => _connection.state == 'error';

@override
bool get inProgress =>
_connection.state != 'closed' && _connection.state != 'error';

@override
bool operator ==(Object other) => other is WebSocket && id == other.id;

@override
int get hashCode => id.hashCode;

@override
Map<String, Object?> toJson() {
return {
'connectionId': connectionId,
'uri': uri,
'protocol': protocol,
'state': state,
'connectTimestamp': startTimestamp.toIso8601String(),
'openTimestamp': _connection.openTimestamp?.toIso8601String(),
'closeTimestamp': endTimestamp?.toIso8601String(),
'bytesSent': bytesSent,
'bytesReceived': bytesReceived,
'framesSent': framesSent,
'framesReceived': framesReceived,
'pingCount': pingCount,
'pongCount': pongCount,
'closeCode': closeCode,
'closeReason': closeReason,
'error': error,
'lastUpdated': lastUpdated.toIso8601String(),
'events': events
.map(
(event) => {
'timestamp': event.timestamp.toIso8601String(),
'event': event.event,
'frameNumber': event.frameNumber,
'direction': event.direction,
'opcode': event.opcode,
'payloadSize': event.payloadSize,
'errorType': event.errorType,
'errorMessage': event.errorMessage,
},
)
.toList(),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class NetworkRequestInspector extends StatelessWidget {
const NetworkRequestInspector({super.key});

static const _overviewTabTitle = 'Overview';
static const _framesTabTitle = 'Frames';
static const _headersTabTitle = 'Headers';
static const _requestTabTitle = 'Request';
static const _responseTabTitle = 'Response';
Expand Down Expand Up @@ -68,6 +69,11 @@ class NetworkRequestInspector extends StatelessWidget {
tab: _buildTab(tabName: NetworkRequestInspector._overviewTabTitle),
tabView: NetworkRequestOverviewView(data),
),
if (data is WebSocket)
(
tab: _buildTab(tabName: NetworkRequestInspector._framesTabTitle),
tabView: WebSocketFramesView(data),
),
if (data is DartIOHttpRequestData) ...[
(
tab: _buildTab(tabName: NetworkRequestInspector._headersTabTitle),
Expand Down
Loading