Skip to content

Commit 34b4c91

Browse files
bkonyicommit-bot@chromium.org
authored andcommitted
[ DDS ] Add getStreamHistory RPC and package:vm_service extensions
Adds a DDS RPC which allows for stream history to be manually requested in addition to being sent upon initial stream subscription. Also adds an initial implementation of package:dds/vm_service_extensions.dart, which adds DDS functionality to the `VmService` class. Fixes #44505 Change-Id: I198a6fd7fca15f131a6fdd95e7860a6f98ef06a7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/177182 Reviewed-by: Kenzie Schmoll <[email protected]> Commit-Queue: Ben Konyi <[email protected]>
1 parent b3f22d0 commit 34b4c91

10 files changed

+195
-7
lines changed

pkg/dds/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 1.7.0
2+
- Added `package:dds/vm_service_extensions.dart`, which adds DDS functionality to
3+
`package:vm_service` when imported.
4+
- Added `getStreamHistory` RPC.
5+
16
# 1.6.1
27
- Fixed unhandled `StateError` that could be thrown if the VM service disconnected
38
while a request was outstanding.

pkg/dds/dds_protocol.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Dart Development Service Protocol 1.1
1+
# Dart Development Service Protocol 1.2
22

3-
This document describes _version 1.1_ of the Dart Development Service Protocol.
3+
This document describes _version 1.2_ of the Dart Development Service Protocol.
44
This protocol is an extension of the Dart VM Service Protocol and implements it
55
in it's entirety. For details on the VM Service Protocol, see the [Dart VM Service Protocol Specification][service-protocol].
66

@@ -103,6 +103,19 @@ disabled.
103103

104104
See [Size](#size).
105105

106+
107+
### getStreamHistory
108+
109+
```
110+
StreamHistory getStreamHistory(string streamId)
111+
```
112+
113+
The _getStreamHistory_ RPC is used to retrieve historical events for streams
114+
which support event history (see [Streams](#streams) for a list of supported
115+
streams).
116+
117+
See [StreamHistory](#streamhistory).
118+
106119
### requirePermissionToResume
107120

108121
```
@@ -189,12 +202,24 @@ class Size extends Response {
189202

190203
A simple object representing a size response.
191204

205+
### StreamHistory
206+
207+
```
208+
class StreamHistory extends Response {
209+
// A list of historical Events for a stream.
210+
List<Event> history;
211+
}
212+
```
213+
214+
See [getStreamHistory](#getStreamHistory).
215+
192216
## Revision History
193217

194218
version | comments
195219
------- | --------
196220
1.0 | Initial revision
197221
1.1 | Added `getDartDevelopmentServiceVersion` RPC.
222+
1.2 | Added `getStreamHistory` RPC.
198223

199224
[resume]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#resume
200225
[success]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#success

pkg/dds/lib/dds.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ abstract class DartDevelopmentService {
129129

130130
/// The version of the DDS protocol supported by this [DartDevelopmentService]
131131
/// instance.
132-
static const String protocolVersion = '1.1';
132+
static const String protocolVersion = '1.2';
133133
}
134134

135135
class DartDevelopmentServiceException implements Exception {

pkg/dds/lib/src/client.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ class DartDevelopmentServiceClient {
148148
(parameters) => dds.isolateManager.resumeIsolate(this, parameters),
149149
);
150150

151+
_clientPeer.registerMethod('getStreamHistory', (parameters) {
152+
final stream = parameters['stream'].asString;
153+
final events = dds.streamManager.getStreamHistory(stream);
154+
if (events == null) {
155+
throw json_rpc.RpcException.invalidParams(
156+
"Event history is not collected for stream '$stream'",
157+
);
158+
}
159+
return <String, dynamic>{
160+
'type': 'StreamHistory',
161+
'history': events,
162+
};
163+
});
164+
151165
_clientPeer.registerMethod(
152166
'getLogHistorySize',
153167
(parameters) => {

pkg/dds/lib/src/stream_manager.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ class StreamManager {
176176
}
177177
}
178178

179+
List<Map<String, dynamic>> getStreamHistory(String stream) {
180+
if (!loggingRepositories.containsKey(stream)) {
181+
return null;
182+
}
183+
return [
184+
for (final event in loggingRepositories[stream]()) event,
185+
];
186+
}
187+
179188
/// Unsubscribes `client` from a stream.
180189
///
181190
/// If `client` is the last client to unsubscribe from `stream`, DDS will
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:collection';
6+
7+
import 'package:meta/meta.dart';
8+
import 'package:vm_service/src/vm_service.dart';
9+
10+
extension DdsExtension on VmService {
11+
static bool _factoriesRegistered = false;
12+
static Version _ddsVersion;
13+
14+
/// The _getDartDevelopmentServiceVersion_ RPC is used to determine what version of
15+
/// the Dart Development Service Protocol is served by a DDS instance.
16+
///
17+
/// The result of this call is cached for subsequent invocations.
18+
Future<Version> getDartDevelopmentServiceVersion() async {
19+
if (_ddsVersion == null) {
20+
_ddsVersion =
21+
await _callHelper<Version>('getDartDevelopmentServiceVersion');
22+
}
23+
return _ddsVersion;
24+
}
25+
26+
/// Retrieve the event history for `stream`.
27+
///
28+
/// If `stream` does not have event history collected, a parameter error is
29+
/// returned.
30+
Future<StreamHistory> getStreamHistory(String stream) async {
31+
if (!(await _versionCheck(1, 2))) {
32+
throw UnimplementedError('getStreamHistory requires DDS version 1.2');
33+
}
34+
return _callHelper<StreamHistory>('getStreamHistory', args: {
35+
'stream': stream,
36+
});
37+
}
38+
39+
Future<bool> _versionCheck(int major, int minor) async {
40+
if (_ddsVersion == null) {
41+
_ddsVersion = await getDartDevelopmentServiceVersion();
42+
}
43+
return ((_ddsVersion.major == major && _ddsVersion.minor >= minor) ||
44+
(_ddsVersion.major > major));
45+
}
46+
47+
Future<T> _callHelper<T>(String method,
48+
{String isolateId, Map args = const {}}) {
49+
if (!_factoriesRegistered) {
50+
_registerFactories();
51+
}
52+
return callMethod(
53+
method,
54+
args: {
55+
if (isolateId != null) 'isolateId': isolateId,
56+
...args,
57+
},
58+
).then((e) => e as T);
59+
}
60+
61+
static void _registerFactories() {
62+
addTypeFactory('StreamHistory', StreamHistory.parse);
63+
_factoriesRegistered = true;
64+
}
65+
}
66+
67+
/// A collection of historical [Event]s from some stream.
68+
class StreamHistory extends Response {
69+
static StreamHistory parse(Map<String, dynamic> json) =>
70+
json == null ? null : StreamHistory._fromJson(json);
71+
72+
StreamHistory({@required List<Event> history}) : _history = history;
73+
74+
StreamHistory._fromJson(Map<String, dynamic> json)
75+
: _history = List<Event>.from(
76+
createServiceObject(json['history'], const ['Event']) as List ??
77+
[]) {
78+
type = json['type'];
79+
}
80+
81+
/// Historical [Event]s for a stream.
82+
List<Event> get history => UnmodifiableListView(_history);
83+
final List<Event> _history;
84+
}

pkg/dds/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: >-
33
A library used to spawn the Dart Developer Service, used to communicate with
44
a Dart VM Service instance.
55
6-
version: 1.6.1
6+
version: 1.7.0
77

88
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
99

@@ -20,10 +20,10 @@ dependencies:
2020
shelf_web_socket: ^0.2.3
2121
sse: ^3.5.0
2222
stream_channel: ^2.0.0
23+
vm_service: ^5.0.0
2324
web_socket_channel: ^1.1.0
2425

2526
dev_dependencies:
2627
shelf_static: ^0.2.8
2728
test: ^1.0.0
28-
vm_service: ^5.0.0
2929
webdriver: ^2.1.2

pkg/dds/test/common/test_helper.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import 'dart:io';
77

88
Uri remoteVmServiceUri;
99

10-
Future<Process> spawnDartProcess(String script) async {
10+
Future<Process> spawnDartProcess(
11+
String script, {
12+
bool pauseOnStart = true,
13+
}) async {
1114
final executable = Platform.executable;
1215
final tmpDir = await Directory.systemTemp.createTemp('dart_service');
1316
final serviceInfoUri = tmpDir.uri.resolve('service_info.json');
@@ -16,7 +19,7 @@ Future<Process> spawnDartProcess(String script) async {
1619
final arguments = [
1720
'--disable-dart-dev',
1821
'--observe=0',
19-
'--pause-isolates-on-start',
22+
if (pauseOnStart) '--pause-isolates-on-start',
2023
'--write-service-info=$serviceInfoUri',
2124
...Platform.executableArguments,
2225
Platform.script.resolve(script).toString(),
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import 'dart:developer';
2+
3+
void main() {
4+
for (int i = 0; i < 10; ++i) {
5+
log(i.toString());
6+
}
7+
debugger();
8+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:io';
6+
7+
import 'package:dds/dds.dart';
8+
import 'package:dds/vm_service_extensions.dart';
9+
import 'package:test/test.dart';
10+
import 'package:vm_service/vm_service_io.dart';
11+
import 'common/test_helper.dart';
12+
13+
void main() {
14+
Process process;
15+
DartDevelopmentService dds;
16+
17+
setUp(() async {
18+
process = await spawnDartProcess('get_stream_history_script.dart',
19+
pauseOnStart: false);
20+
});
21+
22+
tearDown(() async {
23+
await dds?.shutdown();
24+
process?.kill();
25+
dds = null;
26+
process = null;
27+
});
28+
29+
test('getStreamHistory returns log history', () async {
30+
dds = await DartDevelopmentService.startDartDevelopmentService(
31+
remoteVmServiceUri,
32+
);
33+
expect(dds.isRunning, true);
34+
final service = await vmServiceConnectUri(dds.wsUri.toString());
35+
final result = await service.getStreamHistory('Logging');
36+
expect(result, isNotNull);
37+
expect(result, isA<StreamHistory>());
38+
expect(result.history.length, 10);
39+
});
40+
}

0 commit comments

Comments
 (0)