Revert "[ VM / Service ] Pulled in vm_service_drivers from its own repo."

This reverts commit dbeceb1d06.

Reason for revert: Exposes private VM service methods

Original change's description:
> [ VM / Service ] Pulled in vm_service_drivers from its own repo.
> 
> - Updated various paths to point to the sdk repo instead of the
>   vm_service_drivers repo.
> - Updated generate.dart to use the service.md from the SDK, not a copy.
> - Removed hidden files that are no longer needed.
> 
> Change-Id: I11b1f2e32d55f1fdaaa6eb9ce34fc318716c36f9
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109120
> Reviewed-by: Devon Carew <devoncarew@google.com>
> Commit-Queue: Ben Konyi <bkonyi@google.com>

TBR=devoncarew@google.com,bkonyi@google.com,rmacnak@google.com,asiva@google.com

Change-Id: I44af2074ba13dec41ffac3c25330e4603c50b06a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109895
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2019-07-22 20:26:22 +00:00 committed by commit-bot@chromium.org
parent 722b505316
commit 477a3c4748
66 changed files with 0 additions and 15310 deletions

View file

@ -104,7 +104,6 @@ typed_data:third_party/pkg/typed_data/lib
unittest:third_party/pkg/unittest/lib
usage:third_party/pkg/usage/lib
vm:pkg/vm/lib
vm_service:pkg/vm_service/lib
watcher:third_party/pkg/watcher/lib
web_components:third_party/pkg/web_components/lib
web_socket_channel:third_party/pkg/web_socket_channel/lib

View file

@ -1,4 +0,0 @@
*.iml
.dart_tool
.packages
pubspec.lock

View file

@ -1,240 +0,0 @@
# Changelog
## 1.0.0
- Migrated `vm_service_lib` into the Dart SDK.
- Renamed from `package:vm_service_lib` to `package:vm_service`.
- Switched versioning system to follow semantic versioning standards instead of
pinning versions to match the service protocol version.
## 3.22.2
- Fix `registerService` RPC and `Service` stream not being handled correctly.
- Fixed failing tests.
## 3.22.1
- **breaking**: Changed type of `library` property in `Class` objects from
`ObjectRef` to `LibraryRef`.
## 3.22.0
- The `registerService` RPC and `Service` stream are now public.
- `Event` has been updated to include the optional `service`, `method`, and
`alias` properties.
## 3.21.1
- **breaking**: Fixed issue where an `InstanceRef` of type `null` could be returned
instead of null for non-`InstanceRef` properties and return values. As a
result, some property and return types have been changed from Obj to their
correct types.
## 3.21.0
- support service protocol version 3.21
## 3.20.0+2
- allow optional params in `getVMTimeline`
## 3.20.0+1
- handle null isolate ids in `callServiceExtension`
- add backwards compatibility for `InstanceSet` and `AllocationProfile`
## 3.20.0
- rev to 3.20.0; expose public methods added in 3.17 - 3.20 VM Service Protocol versions
## 3.17.0+1
- generate a list of available event streams
## 3.17.0
- rev to 3.17.0; expose the Logging event and the getMemoryUsage call
## 3.15.1+2
- fix handling of errors in registered service callbacks to return valid
JSON-RPC errors and avoid the client getting "Service Disappeared" responses
## 3.15.1+1
- rename `getVmWsUriFromObservatoryUri` to `convertToWebSocketUrl`
- fix an assignment issue in `evaluate`
## 3.15.1
- Add `getVmWsUriFromObservatoryUri`, a helper function to convert observatory URIs
into the required WebSocket URI for connecting to the VM service.
## 3.15.0
- support service protocol version 3.15
- fix an issue decoding null `Script.tokenPosTable` values
## 3.14.3-dev.4
- Add support for the `_Service` stream in the `VmServerConnection` directly.
## 3.14.3-dev.3
- Add support for automatically delegating service extension requests to the
client which registered them.
- This is only for services that are registered via the vm service protocol,
services registered through `dart:developer` should be handled by the
`VmServiceInterface` implementation (which should invoke the registered
callback directly).
- Added a `ServiceExtensionRegistry` class, which tracks which clients have
registered which service extensions.
- **breaking**: Renamed `VmServer` to `VmServerConnection`.
- One `VmServerConnection` should be created _per client_ connection to the
server. These should typically all share the same underlying
`VmServiceInterface` instance, as well as the same
`ServiceExtensionRegistry` instance.
## 3.14.3-dev.2
- Add `callServiceExtension` method to the `VmServiceInterface` class.
- The `VmServer` will delegate all requests whose methods start with `ext.` to
that implementation.
## 3.14.3-dev.1
- Add `VmServiceInterface` and `VmServer` classes, which can handle routing
jsonrpc2 requests to a `VmServiceInterface` instance, and serializing the
responses back.
## 3.14.3-dev.0
- Add `toJson` methods to all classes.
## 3.14.2
- fix code generation for the `getSourceReport` call
## 3.14.1
- address an encoding issue with stdout / stderr text
## 3.14.0
- regenerate for `v3.14`
- bump to a major version numbering scheme
## 0.3.10+2
- work around an issue de-serializing Instance.closureContext
## 0.3.10+1
- fix an issue de-serializing some object types
## 0.3.10
- regenerate for `v3.12`
- expose `isolate.getScripts()`
- expose `isolate.getInstances()`
## 0.3.9+2
- handle nulls for `Script.source`
- fix a decoding issue for `Script.tokenPosTable`
## 0.3.9+1
- rev to version `3.9` of the spec
- expose `invoke`
## 0.3.9
- Rename the `Null` type to `NullVal`
## 0.3.8
- upgrades for Dart 2 dependencies
## 0.3.7
- ensure the library works with Dart 2
- regenerate the library based on the 3.8-dev spec
- now require a minimum of a 2.0.0-dev Dart SDK
- update to not use deprecated dart:convert constants
## 0.3.6
- workaround for an issue with the type of @Library refs for VM objects
## 0.3.5+1
- bug fix for deserializing `Instance` objects
## 0.3.5
- improve access to the profiling APIs
## 0.3.4
- more strong mode runtime fixes
- expose some undocumented (and unsupported) service protocol methods
## 0.3.3
- fix strong mode issues at runtime (with JSLists and Lists)
- expose the ability to evaluate in the scope of another object
- expose the async causal frame info
- expose the `awaiterFrames` field
- expose the `frameIndex` param for the step call
## 0.3.2+1
- fix a strong mode issue in the generated Dart library
## 0.3.2
- expose the `PausePostRequest` event
## 0.3.1
- fix a parsing issue with ExtensionData
## 0.2.4
- expose the service protocol timeline API
- add the new `None` event type
## 0.2.3
- include the name of the calling method in RPC errors
## 0.2.2
- fixed several strong mode analysis issues
## 0.2.1
- upgrade to service protocol version `3.3`
## 0.2.0
- upgrade to service protocol version `3.2`
## 0.1.2
- fixed a bug with the `ServiceExtensionAdded` event
## 0.1.1
- expose the new 'Extension' event information
## 0.1.0
- rev to 0.1.0; declare first stable API version
## 0.0.13
- improve the toString() message for RPCError
## 0.0.12
- bug fix for parsing MapAssociations
## 0.0.11
- bug fix to the service extension API
## 0.0.10
- expose a service extension API
## 0.0.9
- update to the latest spec to capture the `Event.inspectee` field
## 0.0.8
- allow listening to arbitrary event types
- use Strings for the enum types (to allow for unknown enum values)
## 0.0.7
- make the diagnostic logging synchronous
- remove a workaround for a VM bug (fixed in 1.13.0-dev.7.3)
- several strong mode fixes
## 0.0.6
- added `exceptionPauseMode` to the Isolate class
- added `hashCode` and `operator==` methods to classes supporting object identity
- work around a VM bug with the `type` field of `BoundVariable` and `BoundField`
## 0.0.5
- added more dartdocs
- moved back to using Dart enums
- changed from optional positional params to optional named params
## 0.0.4
- enum redux
## 0.0.3
- update to use a custom enum class
- upgrade to the latest service protocol spec
## 0.0.2
- added the `setExceptionPauseMode` method
- fixed an issue with enum parsing
## 0.0.1
- first publish
- upgraded the library to the 3.0 version of the service protocol
- upgraded the library to the 2.0 version of the service protocol
- copied basic Dart API generator from Atom Dart Plugin
https://github.com/dart-atom/dartlang/tree/master/tool
- refactored Dart code to generate Java client as well as Dart client

View file

@ -1,26 +0,0 @@
Copyright 2015, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,20 +0,0 @@
# vm_service
[![pub package](https://img.shields.io/pub/v/vm_service.svg)](https://pub.dartlang.org/packages/vm_service)
A library to access the VM Service Protocol.
## Usage
See the
[example](https://github.com/dart-lang/sdk/blob/master/pkg/vm_service/example/vm_service_tester.dart)
for a simple use of the library's API.
The VM Service Protocol spec can be found at
[github.com/dart-lang/sdk/runtime/vm/service/service.md](https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md).
## Features and bugs
Please file feature requests and bugs at the [issue tracker][tracker].
[tracker]: https://github.com/dart-lang/sdk/issues

View file

@ -1,6 +0,0 @@
include: package:pedantic/analysis_options.1.7.0.yaml
linter:
rules:
- directives_ordering
- prefer_generic_function_type_aliases

View file

@ -1,54 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:isolate';
main(List<String> args) async {
var arr = newArray(5);
var arr2 = newArray(417);
var hash1 = newHash(5);
var hash2 = newHash(417);
// ignore unused
arr.length;
arr2.length;
hash1.length;
hash2.length;
startIsolate(1);
startIsolate(2);
startIsolate(3);
startIsolate(4);
await new Future.delayed(new Duration(seconds: 5));
print('at end of main...');
}
void startIsolate(int val) {
Isolate.spawn(isolateEntry, val);
}
isolateEntry(message) async {
print('starting $message');
await new Future.delayed(new Duration(seconds: message));
print('ending $message');
}
List newArray(int length) {
List l = [];
for (int i = 0; i < length; i++) {
l.add('entry_$i');
}
return l;
}
Map newHash(int length) {
Map m = {};
for (int i = 0; i < length; i++) {
m['entry_$i'] = i;
}
return m;
}

View file

@ -1,50 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:developer' as developer;
void main(List<String> args) {
String local1 = 'abcd';
int local2 = 2;
var longList = [1, "hello", 3, 5, 7, 11, 13, 14, 15, 16, 17, 18, 19, 20];
var deepList = [
new Bar(),
[
[
[
[
[7]
]
],
"end"
]
]
];
print('hello from main');
foo(1);
foo(local2);
foo(3);
foo(local1.length);
print(longList);
print(deepList);
developer.debugger();
print('exiting...');
}
void foo(int val) {
print('val: ${val}');
}
class Bar extends FooBar {
String field1 = "my string";
}
class FooBar {
int field2 = 47;
}

File diff suppressed because it is too large Load diff

View file

@ -1,219 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library service_tester;
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:pedantic/pedantic.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'package:vm_service/vm_service_io.dart';
final String host = 'localhost';
final int port = 7575;
VmService serviceClient;
void main() {
Process process;
tearDown(() {
process?.kill();
});
test('integration', () async {
String sdk = path.dirname(path.dirname(Platform.resolvedExecutable));
print('Using sdk at ${sdk}.');
// pause_isolates_on_start, pause_isolates_on_exit
process = await Process.start('${sdk}/bin/dart', [
'--pause_isolates_on_start',
'--enable-vm-service=${port}',
'--disable-service-auth-codes',
'example/sample_main.dart'
]);
print('dart process started');
// ignore: unawaited_futures
process.exitCode.then((code) => print('vm exited: ${code}'));
// ignore: strong_mode_down_cast_composite
process.stdout.transform(utf8.decoder).listen(print);
// ignore: strong_mode_down_cast_composite
process.stderr.transform(utf8.decoder).listen(print);
await new Future.delayed(new Duration(milliseconds: 500));
serviceClient = await vmServiceConnect(host, port, log: new StdoutLog());
print('socket connected');
serviceClient.onSend.listen((str) => print('--> ${str}'));
// The next listener will bail out if you toggle this to false, which we need
// to do for some things like the custom service registration tests.
var checkResponseJsonCompatibility = true;
serviceClient.onReceive.listen((str) {
print('<-- ${str}');
if (!checkResponseJsonCompatibility) return;
// For each received event, check that we can deserialize it and
// reserialize it back to the same exact representation (minus private
// fields).
var json = jsonDecode(str);
var originalJson = json['result'] as Map<String, dynamic>;
if (originalJson == null && json['method'] == 'streamNotify') {
originalJson = json['params']['event'];
}
expect(originalJson, isNotNull, reason: 'Unrecognized event type! $json');
// ignore: invalid_use_of_visible_for_testing_member
var instance =
createServiceObject(originalJson, const ['Event', 'Success']);
expect(instance, isNotNull,
reason: 'failed to deserialize object $originalJson!');
var reserializedJson = (instance as dynamic).toJson();
forEachNestedMap(originalJson, (obj) {
// Private fields that we don't reproduce
obj.removeWhere((k, v) => k.startsWith('_'));
// Extra fields that aren't specified and we don't reproduce
obj.remove('isExport');
});
forEachNestedMap(reserializedJson, (obj) {
// We provide explicit defaults for these, need to remove them.
obj.remove('valueAsStringIsTruncated');
});
expect(reserializedJson, equals(originalJson));
});
serviceClient.onIsolateEvent.listen((e) => print('onIsolateEvent: ${e}'));
serviceClient.onDebugEvent.listen((e) => print('onDebugEvent: ${e}'));
serviceClient.onGCEvent.listen((e) => print('onGCEvent: ${e}'));
serviceClient.onStdoutEvent.listen((e) => print('onStdoutEvent: ${e}'));
serviceClient.onStderrEvent.listen((e) => print('onStderrEvent: ${e}'));
unawaited(serviceClient.streamListen(EventStreams.kIsolate));
unawaited(serviceClient.streamListen(EventStreams.kDebug));
unawaited(serviceClient.streamListen(EventStreams.kStdout));
VM vm = await serviceClient.getVM();
print('hostCPU=${vm.hostCPU}');
print(await serviceClient.getVersion());
List<IsolateRef> isolates = await vm.isolates;
print(isolates);
// Disable the json reserialization checks since custom services are not
// supported.
checkResponseJsonCompatibility = false;
await testServiceRegistration();
checkResponseJsonCompatibility = true;
await testScriptParse(vm.isolates.first);
await testSourceReport(vm.isolates.first);
IsolateRef isolateRef = isolates.first;
print(await serviceClient.resume(isolateRef.id));
serviceClient.dispose();
});
}
// Deeply traverses a map and calls [cb] with each nested map and the
// parent map.
void forEachNestedMap(Map input, Function(Map) cb) {
var queue = Queue.from([input]);
while (queue.isNotEmpty) {
var next = queue.removeFirst();
if (next is Map) {
cb(next);
queue.addAll(next.values);
} else if (next is List) {
queue.addAll(next);
}
}
}
Future testServiceRegistration() async {
const String serviceName = 'serviceName';
const String serviceAlias = 'serviceAlias';
const String movedValue = 'movedValue';
serviceClient.registerServiceCallback(serviceName,
(Map<String, dynamic> params) async {
assert(params['input'] == movedValue);
return <String, dynamic>{
'result': {'output': params['input']}
};
});
await serviceClient.registerService(serviceName, serviceAlias);
VmService otherClient =
await vmServiceConnect(host, port, log: new StdoutLog());
Completer completer = new Completer();
otherClient.onEvent('_Service').listen((e) async {
if (e.service == serviceName && e.kind == EventKind.kServiceRegistered) {
assert(e.alias == serviceAlias);
Response response = await serviceClient.callMethod(
e.method,
args: <String, dynamic>{'input': movedValue},
);
assert(response.json['output'] == movedValue);
completer.complete();
}
});
await otherClient.streamListen('_Service');
await completer.future;
}
Future testScriptParse(IsolateRef isolateRef) async {
final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
final Library rootLibrary =
await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
final ScriptRef scriptRef = rootLibrary.scripts.first;
final Script script =
await serviceClient.getObject(isolateRef.id, scriptRef.id);
print(script);
print(script.uri);
print(script.library);
print(script.source.length);
print(script.tokenPosTable.length);
}
Future testSourceReport(IsolateRef isolateRef) async {
final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
final Library rootLibrary =
await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
final ScriptRef scriptRef = rootLibrary.scripts.first;
// make sure some code has run
await serviceClient.resume(isolateRef.id);
await Future.delayed(const Duration(milliseconds: 25));
final SourceReport sourceReport = await serviceClient.getSourceReport(
isolateRef.id, [SourceReportKind.kCoverage],
scriptId: scriptRef.id);
for (SourceReportRange range in sourceReport.ranges) {
print(' $range');
if (range.coverage != null) {
print(' ${range.coverage}');
}
}
print(sourceReport);
}
class StdoutLog extends Log {
void warning(String message) => print(message);
void severe(String message) => print(message);
}

View file

@ -1,4 +0,0 @@
build/
dist/
out/
src/gen/

View file

@ -1,54 +0,0 @@
<project name="vm_service_lib" default="dist">
<target name="clean">
<delete dir="build"/>
</target>
<target name="init">
<mkdir dir="build"/>
<mkdir dir="dist"/>
<property environment="env"/>
<property file="version.properties" prefix="service"/>
<property name="build.id" value=""/>
<property
name="path"
value="third_party/gson/gson-2.2.4.jar;third_party/guava/guava-13.0.1.jar;third_party/weberknecht/weberknecht-0.1.5.jar"/>
</target>
<target name="compile" depends="init">
<!-- compile library source -->
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes" includeantruntime="false"
source="1.7" target="1.7"
classpath="${path}" debug="true"/>
<!-- compile tests -->
<mkdir dir="build/test"/>
<javac srcdir="test" destdir="build/test" includeantruntime="false"
classpath="${path};build/classes" debug="true"/>
</target>
<target name="jar" depends="compile">
<copy file="version.properties" todir="build/classes"/>
<jar destfile="build/vm_service_lib.jar" basedir="build/classes"/>
<jar destfile="build/vm_service_lib-src.jar" basedir="src"/>
</target>
<target name="test" depends="compile">
<java classname="org.dartlang.vm.service.VmServiceTest" fork="true" failonerror="true">
<arg value="${env.DART_SDK}"/>
<classpath>
<pathelement path="${path}"/>
<pathelement location="build/classes"/>
<pathelement location="build/test"/>
</classpath>
</java>
</target>
<target name="dist" depends="jar,test">
<!-- copy and rename the library -->
<copy file="build/vm_service_lib.jar" tofile="dist/vm_service_lib-${service.version}${build.id}.jar"/>
<copy file="build/vm_service_lib-src.jar" tofile="dist/vm_service_lib-${service.version}${build.id}-src.jar"/>
</target>
</project>

View file

@ -1 +0,0 @@
third_party/gson/gson-2.2.4.jar:third_party/guava/guava-13.0.1.jar:third_party/weberknecht/weberknecht-0.1.5.jar

View file

@ -1,53 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
void main(List<String> args) {
// Hijinks to remove an analysis warning.
dynamic local1;
if (true) local1 = 'abcd';
int local2 = 2;
var longList = [1, "hello", 3, 5, 7, 11, 13, 14, 15, 16, 17, 18, 19, 20];
var deepList = [
new Bar(),
[
[
[
[
[7]
]
],
"end"
]
]
];
print('hello from main');
// throw a caught exception
try {
foo(local1.baz());
} catch (e) {
print('-----------------');
print('caught $e');
print('-----------------');
}
foo(local2);
print(longList);
print(deepList);
print('exiting...');
}
void foo(int val) {
print('val: ${val}');
}
class Bar extends FooBar {
String field1 = "my string";
}
class FooBar {
int field2 = 47;
}

View file

@ -1,46 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
void main(List<String> args) {
String local1 = 'abcd';
int local2 = 2;
var longList = [1, "hello", 3, 5, 7, 11, 13, 14, 15, 16, 17, 18, 19, 20];
var deepList = [
new Bar(),
[
[
[
[
[7]
]
],
"end"
]
]
];
print('hello from main');
foo(1);
foo(local2);
foo(3);
foo(local1.length);
print(longList);
print(deepList);
print('exiting...');
}
void foo(int val) {
print('val: ${val}');
}
class Bar extends FooBar {
String field1 = "my string";
}
class FooBar {
int field2 = 47;
}

View file

@ -1,5 +0,0 @@
{
"sourcePath": ["src", "test"],
"classPathFile": "classpath.txt",
"outputDirectory": "build/classes"
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2017, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import com.google.gson.JsonObject;
public interface RemoteServiceCompleter {
/**
* Should be called when a service request completes successfully.
*
* @param result the result of the request
*/
void result(JsonObject result);
/**
* Should be called when a service request completes with an error.
*
* @param code the error code generated by the request
* @param message the description of the error
* @param data [optional] the description of the error
*/
void error(int code, String message, JsonObject data);
}

View file

@ -1,29 +0,0 @@
/*
* Copyright (c) 2017, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import com.google.gson.JsonObject;
/**
* Interface used by {@link VmService} to register callbacks to services.
*/
public interface RemoteServiceRunner {
/**
* Called when a service request has been received.
*
* @param params the parameters of the request
* @param completer the completer to invoke at the end of the execution
*/
void run(JsonObject params, RemoteServiceCompleter completer);
}

View file

@ -1,635 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.roderick.weberknecht.WebSocket;
import de.roderick.weberknecht.WebSocketEventHandler;
import de.roderick.weberknecht.WebSocketException;
import de.roderick.weberknecht.WebSocketMessage;
import org.dartlang.vm.service.consumer.*;
import org.dartlang.vm.service.element.*;
import org.dartlang.vm.service.internal.RequestSink;
import org.dartlang.vm.service.internal.VmServiceConst;
import org.dartlang.vm.service.internal.WebSocketRequestSink;
import org.dartlang.vm.service.logging.Logging;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Internal {@link VmService} base class containing non-generated code.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
abstract class VmServiceBase implements VmServiceConst {
/**
* Connect to the VM observatory service via the specified URI
*
* @return an API object for interacting with the VM service (not {@code null}).
*/
public static VmService connect(final String url) throws IOException {
// Validate URL
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new IOException("Invalid URL: " + url, e);
}
String wsScheme = uri.getScheme();
if (!"ws".equals(wsScheme) && !"wss".equals(wsScheme)) {
throw new IOException("Unsupported URL scheme: " + wsScheme);
}
// Create web socket and observatory
WebSocket webSocket;
try {
webSocket = new WebSocket(uri);
} catch (WebSocketException e) {
throw new IOException("Failed to create websocket: " + url, e);
}
final VmService vmService = new VmService();
// Setup event handler for forwarding responses
webSocket.setEventHandler(new WebSocketEventHandler() {
@Override
public void onClose() {
Logging.getLogger().logInformation("VM connection closed: " + url);
vmService.connectionClosed();
}
@Override
public void onMessage(WebSocketMessage message) {
Logging.getLogger().logInformation("VM message: " + message.getText());
try {
vmService.processMessage(message.getText());
} catch (Exception e) {
Logging.getLogger().logError(e.getMessage(), e);
}
}
@Override
public void onOpen() {
vmService.connectionOpened();
Logging.getLogger().logInformation("VM connection open: " + url);
}
@Override
public void onPing() {
}
@Override
public void onPong() {
}
});
// Establish WebSocket Connection
//noinspection TryWithIdenticalCatches
try {
webSocket.connect();
} catch (WebSocketException e) {
throw new IOException("Failed to connect: " + url, e);
} catch (ArrayIndexOutOfBoundsException e) {
// The weberknecht can occasionally throw an array index exception if a connect terminates on initial connect
// (de.roderick.weberknecht.WebSocket.connect, WebSocket.java:126).
throw new IOException("Failed to connect: " + url, e);
}
vmService.requestSink = new WebSocketRequestSink(webSocket);
// Check protocol version
final CountDownLatch latch = new CountDownLatch(1);
final String[] errMsg = new String[1];
vmService.getVersion(new VersionConsumer() {
@Override
public void onError(RPCError error) {
String msg = "Failed to determine protocol version: " + error.getCode() + "\n message: "
+ error.getMessage() + "\n details: " + error.getDetails();
Logging.getLogger().logInformation(msg);
errMsg[0] = msg;
}
@Override
public void received(Version response) {
int major = response.getMajor();
int minor = response.getMinor();
if (major != VmService.versionMajor || minor != VmService.versionMinor) {
if (major == 2 || major == 3) {
Logging.getLogger().logInformation(
"Difference in protocol version: client=" + VmService.versionMajor + "."
+ VmService.versionMinor + " vm=" + major + "." + minor);
} else {
String msg = "Incompatible protocol version: client=" + VmService.versionMajor + "."
+ VmService.versionMinor + " vm=" + major + "." + minor;
Logging.getLogger().logError(msg);
errMsg[0] = msg;
}
}
latch.countDown();
}
});
try {
if (!latch.await(5, TimeUnit.SECONDS)) {
throw new IOException("Failed to determine protocol version");
}
if (errMsg[0] != null) {
throw new IOException(errMsg[0]);
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for response", e);
}
return vmService;
}
/**
* Connect to the VM observatory service on the given local port.
*
* @return an API object for interacting with the VM service (not {@code null}).
*
* @deprecated prefer the Url based constructor {@link VmServiceBase#connect}
*/
@Deprecated
public static VmService localConnect(int port) throws IOException {
return connect("ws://localhost:" + port + "/ws");
}
/**
* A mapping between {@link String} ids' and the associated {@link Consumer} that was passed when
* the request was made. Synchronize against {@link #consumerMapLock} before accessing this field.
*/
private final Map<String, Consumer> consumerMap = Maps.newHashMap();
/**
* The object used to synchronize access to {@link #consumerMap}.
*/
private final Object consumerMapLock = new Object();
/**
* The unique ID for the next request.
*/
private final AtomicInteger nextId = new AtomicInteger();
/**
* A list of objects to which {@link Event}s from the VM are forwarded.
*/
private final List<VmServiceListener> vmListeners = new ArrayList<>();
/**
* A list of objects to which {@link Event}s from the VM are forwarded.
*/
private final Map<String, RemoteServiceRunner> remoteServiceRunners = Maps.newHashMap();
/**
* The channel through which observatory requests are made.
*/
RequestSink requestSink;
/**
* Add a listener to receive {@link Event}s from the VM.
*/
public void addVmServiceListener(VmServiceListener listener) {
vmListeners.add(listener);
}
/**
* Remove the given listener from the VM.
*/
public void removeVmServiceListener(VmServiceListener listener) {
vmListeners.remove(listener);
}
/**
* Add a VM RemoteServiceRunner.
*/
public void addServiceRunner(String service, RemoteServiceRunner runner) {
remoteServiceRunners.put(service, runner);
}
/**
* Remove a VM RemoteServiceRunner.
*/
public void removeServiceRunner(String service) {
remoteServiceRunners.remove(service);
}
/**
* Disconnect from the VM observatory service.
*/
public void disconnect() {
requestSink.close();
}
/**
* Return the instance with the given identifier.
*/
public void getInstance(String isolateId, String instanceId, final GetInstanceConsumer consumer) {
getObject(isolateId, instanceId, new GetObjectConsumer() {
@Override
public void onError(RPCError error) {
consumer.onError(error);
}
@Override
public void received(Obj response) {
if (response instanceof Instance) {
consumer.received((Instance) response);
} else {
onError(RPCError.unexpected("Instance", response));
}
}
@Override
public void received(Sentinel response) {
onError(RPCError.unexpected("Instance", response));
}
});
}
/**
* Return the library with the given identifier.
*/
public void getLibrary(String isolateId, String libraryId, final GetLibraryConsumer consumer) {
getObject(isolateId, libraryId, new GetObjectConsumer() {
@Override
public void onError(RPCError error) {
consumer.onError(error);
}
@Override
public void received(Obj response) {
if (response instanceof Library) {
consumer.received((Library) response);
} else {
onError(RPCError.unexpected("Library", response));
}
}
@Override
public void received(Sentinel response) {
onError(RPCError.unexpected("Library", response));
}
});
}
public abstract void getObject(String isolateId, String objectId, GetObjectConsumer consumer);
/**
* Invoke a specific service protocol extension method.
* <p>
* See https://api.dartlang.org/stable/dart-developer/dart-developer-library.html.
*/
public void callServiceExtension(String isolateId, String method, ServiceExtensionConsumer consumer) {
JsonObject params = new JsonObject();
params.addProperty("isolateId", isolateId);
request(method, params, consumer);
}
/**
* Invoke a specific service protocol extension method.
* <p>
* See https://api.dartlang.org/stable/dart-developer/dart-developer-library.html.
*/
public void callServiceExtension(String isolateId, String method, JsonObject params, ServiceExtensionConsumer consumer) {
params.addProperty("isolateId", isolateId);
request(method, params, consumer);
}
/**
* Sends the request and associates the request with the passed {@link Consumer}.
*/
protected void request(String method, JsonObject params, Consumer consumer) {
// Assemble the request
String id = Integer.toString(nextId.incrementAndGet());
JsonObject request = new JsonObject();
request.addProperty(JSONRPC, JSONRPC_VERSION);
request.addProperty(ID, id);
request.addProperty(METHOD, method);
request.add(PARAMS, params);
// Cache the consumer to receive the response
synchronized (consumerMapLock) {
consumerMap.put(id, consumer);
}
// Send the request
requestSink.add(request);
}
public void connectionOpened() {
for (VmServiceListener listener : new ArrayList<>(vmListeners)) {
try {
listener.connectionOpened();
} catch (Exception e) {
Logging.getLogger().logError("Exception notifying listener", e);
}
}
}
private void forwardEvent(String streamId, Event event) {
for (VmServiceListener listener : new ArrayList<>(vmListeners)) {
try {
listener.received(streamId, event);
} catch (Exception e) {
Logging.getLogger().logError("Exception processing event: " + streamId + ", " + event.getJson(), e);
}
}
}
public void connectionClosed() {
for (VmServiceListener listener : new ArrayList<>(vmListeners)) {
try {
listener.connectionClosed();
} catch (Exception e) {
Logging.getLogger().logError("Exception notifying listener", e);
}
}
}
abstract void forwardResponse(Consumer consumer, String type, JsonObject json);
void logUnknownResponse(Consumer consumer, JsonObject json) {
Class<? extends Consumer> consumerClass = consumer.getClass();
StringBuilder msg = new StringBuilder();
msg.append("Expected response for ").append(consumerClass).append("\n");
for (Class<?> interf : consumerClass.getInterfaces()) {
msg.append(" implementing ").append(interf).append("\n");
}
msg.append(" but received ").append(json);
Logging.getLogger().logError(msg.toString());
}
/**
* Process the response from the VM service and forward that response to the consumer associated
* with the response id.
*/
void processMessage(String jsonText) {
if (jsonText == null || jsonText.isEmpty()) {
return;
}
// Decode the JSON
JsonObject json;
try {
json = (JsonObject) new JsonParser().parse(jsonText);
} catch (Exception e) {
Logging.getLogger().logError("Parse message failed: " + jsonText, e);
return;
}
if (json.has("method")) {
if (!json.has(PARAMS)) {
final String message = "Missing " + PARAMS;
Logging.getLogger().logError(message);
final JsonObject response = new JsonObject();
response.addProperty(JSONRPC, JSONRPC_VERSION);
final JsonObject error = new JsonObject();
error.addProperty(CODE, INVALID_REQUEST);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
return;
}
if (json.has("id")) {
processRequest(json);
} else {
processNotification(json);
}
} else if (json.has("result") || json.has("error")) {
processResponse(json);
} else {
Logging.getLogger().logError("Malformed message");
}
}
void processRequest(JsonObject json) {
final JsonObject response = new JsonObject();
response.addProperty(JSONRPC, JSONRPC_VERSION);
// Get the consumer associated with this request
String id;
try {
id = json.get(ID).getAsString();
} catch (Exception e) {
final String message = "Request malformed " + ID;
Logging.getLogger().logError(message, e);
final JsonObject error = new JsonObject();
error.addProperty(CODE, INVALID_REQUEST);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
return;
}
response.addProperty(ID, id);
String method;
try {
method = json.get(METHOD).getAsString();
} catch (Exception e) {
final String message = "Request malformed " + METHOD;
Logging.getLogger().logError(message, e);
final JsonObject error = new JsonObject();
error.addProperty(CODE, INVALID_REQUEST);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
return;
}
JsonObject params;
try {
params = json.get(PARAMS).getAsJsonObject();
} catch (Exception e) {
final String message = "Request malformed " + METHOD;
Logging.getLogger().logError(message, e);
final JsonObject error = new JsonObject();
error.addProperty(CODE, INVALID_REQUEST);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
return;
}
if (!remoteServiceRunners.containsKey(method)) {
final String message = "Unknown service " + method;
Logging.getLogger().logError(message);
final JsonObject error = new JsonObject();
error.addProperty(CODE, METHOD_NOT_FOUND);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
return;
}
final RemoteServiceRunner runner = remoteServiceRunners.get(method);
try {
runner.run(params, new RemoteServiceCompleter() {
public void result(JsonObject result) {
response.add(RESULT, result);
requestSink.add(response);
}
public void error(int code, String message, JsonObject data) {
final JsonObject error = new JsonObject();
error.addProperty(CODE, code);
error.addProperty(MESSAGE, message);
if (data != null) {
error.add(DATA, data);
}
response.add(ERROR, error);
requestSink.add(response);
}
});
} catch (Exception e) {
final String message = "Internal Server Error";
Logging.getLogger().logError(message, e);
final JsonObject error = new JsonObject();
error.addProperty(CODE, SERVER_ERROR);
error.addProperty(MESSAGE, message);
response.add(ERROR, error);
requestSink.add(response);
}
}
private static final RemoteServiceCompleter ignoreCallback =
new RemoteServiceCompleter() {
public void result(JsonObject result) {
// ignore
}
public void error(int code, String message, JsonObject data) {
// ignore
}
};
void processNotification(JsonObject json) {
String method;
try {
method = json.get(METHOD).getAsString();
} catch (Exception e) {
Logging.getLogger().logError("Request malformed " + METHOD, e);
return;
}
JsonObject params;
try {
params = json.get(PARAMS).getAsJsonObject();
} catch (Exception e) {
Logging.getLogger().logError("Event missing " + PARAMS, e);
return;
}
if ("streamNotify".equals(method)) {
String streamId;
try {
streamId = params.get(STREAM_ID).getAsString();
} catch (Exception e) {
Logging.getLogger().logError("Event missing " + STREAM_ID, e);
return;
}
Event event;
try {
event = new Event(params.get(EVENT).getAsJsonObject());
} catch (Exception e) {
Logging.getLogger().logError("Event missing " + EVENT, e);
return;
}
forwardEvent(streamId, event);
} else {
if (!remoteServiceRunners.containsKey(method)) {
Logging.getLogger().logError("Unknown service " + method);
return;
}
final RemoteServiceRunner runner = remoteServiceRunners.get(method);
try {
runner.run(params, ignoreCallback);
} catch (Exception e) {
Logging.getLogger().logError("Internal Server Error", e);
}
}
}
void processResponse(JsonObject json) {
JsonElement idElem = json.get(ID);
if (idElem == null) {
Logging.getLogger().logError("Response missing " + ID);
return;
}
// Get the consumer associated with this response
String id;
try {
id = idElem.getAsString();
} catch (Exception e) {
Logging.getLogger().logError("Response missing " + ID, e);
return;
}
Consumer consumer = consumerMap.remove(id);
if (consumer == null) {
Logging.getLogger().logError("No consumer associated with " + ID + ": " + id);
return;
}
// Forward the response if the request was successfully executed
JsonElement resultElem = json.get(RESULT);
if (resultElem != null) {
JsonObject result;
try {
result = resultElem.getAsJsonObject();
} catch (Exception e) {
Logging.getLogger().logError("Response has invalid " + RESULT, e);
return;
}
String responseType;
try {
responseType = result.get(TYPE).getAsString();
} catch (Exception e) {
Logging.getLogger().logError("Response missing " + TYPE, e);
return;
}
forwardResponse(consumer, responseType, result);
return;
}
// Forward an error if the request failed
resultElem = json.get(ERROR);
if (resultElem != null) {
JsonObject error;
try {
error = resultElem.getAsJsonObject();
} catch (Exception e) {
Logging.getLogger().logError("Response has invalid " + RESULT, e);
return;
}
consumer.onError(new RPCError(error));
return;
}
Logging.getLogger().logError("Response missing " + RESULT + " and " + ERROR);
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import org.dartlang.vm.service.element.Event;
/**
* Interface used by {@link VmService} to notify others of VM events.
*/
public interface VmServiceListener {
void connectionOpened();
/**
* Called when a VM event has been received.
*
* @param streamId the stream identifier (e.g. {@link VmService#DEBUG_STREAM_ID}
* @param event the event
*/
void received(String streamId, Event event);
void connectionClosed();
}

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.consumer;
import org.dartlang.vm.service.element.RPCError;
/**
* Consumer is a common interface for all consumer interfaces.
*/
public interface Consumer {
/**
* Called if the request failed for some reason.
*/
void onError(RPCError error);
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.consumer;
import org.dartlang.vm.service.element.Instance;
public interface GetInstanceConsumer extends Consumer {
void received(Instance response);
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.consumer;
import org.dartlang.vm.service.element.Library;
public interface GetLibraryConsumer extends Consumer {
void received(Library response);
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2017, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.consumer;
import com.google.gson.JsonObject;
public interface ServiceExtensionConsumer extends Consumer {
void received(JsonObject result);
}

View file

@ -1,73 +0,0 @@
package org.dartlang.vm.service.element;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.List;
/**
* Superclass for all observatory elements.
*/
public class Element {
protected final JsonObject json;
public Element(JsonObject json) {
this.json = json;
}
/**
* Return the underlying JSON backing this element.
*/
public JsonObject getJson() {
return json;
}
/**
* Return a specific JSON member as a list of integers.
*/
List<Integer> getListInt(String memberName) {
return jsonArrayToListInt(json.getAsJsonArray(memberName));
}
/**
* Return a specific JSON member as a list of strings.
*/
List<String> getListString(String memberName) {
return jsonArrayToListString(json.getAsJsonArray(memberName));
}
/**
* Return a specific JSON member as a list of list of integers.
*/
List<List<Integer>> getListListInt(String memberName) {
JsonArray array = json.getAsJsonArray(memberName);
if (array == null) {
return null;
}
int size = array.size();
List<List<Integer>> result = new ArrayList<>();
for (int index = 0; index < size; ++index) {
result.add(jsonArrayToListInt(array.get(index).getAsJsonArray()));
}
return result;
}
private List<Integer> jsonArrayToListInt(JsonArray array) {
int size = array.size();
List<Integer> result = new ArrayList<>();
for (int index = 0; index < size; ++index) {
result.add(array.get(index).getAsInt());
}
return result;
}
private List<String> jsonArrayToListString(JsonArray array) {
int size = array.size();
List<String> result = new ArrayList<>();
for (int index = 0; index < size; ++index) {
result.add(array.get(index).getAsString());
}
return result;
}
}

View file

@ -1,56 +0,0 @@
package org.dartlang.vm.service.element;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.Iterator;
/**
* Simple wrapper around a {@link JsonArray} which lazily converts {@link JsonObject} elements to
* subclasses of {@link Element}. Subclasses need only implement {@link #basicGet(JsonArray, int)}
* to return an {@link Element} subclass for the {@link JsonObject} at a given index.
*/
public abstract class ElementList<T> implements Iterable<T> {
private final JsonArray array;
public ElementList(JsonArray array) {
this.array = array;
}
public T get(int index) {
return basicGet(array, index);
}
public boolean isEmpty() {
return size() == 0;
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
int index = 0;
@Override
public boolean hasNext() {
return index < size();
}
@Override
public T next() {
return get(index++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public int size() {
return array.size();
}
protected abstract T basicGet(JsonArray array, int index);
}

View file

@ -1,110 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.element;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.dartlang.vm.service.internal.VmServiceConst;
/**
* When an RPC encounters an error, it is provided in the _error_ property of the response object.
* JSON-RPC errors always provide _code_, _message_, and _data_ properties. <br/>
* Here is an example error response for our [streamListen](#streamlisten) request above. This error
* would be generated if we were attempting to subscribe to the _GC_ stream multiple times from the
* same client.
*
* <pre>
* {
* "jsonrpc": "2.0",
* "error": {
* "code": 103,
* "message": "Stream already subscribed",
* "data": {
* "details": "The stream 'GC' is already subscribed"
* }
* }
* "id": "2"
* }
* </pre>
* <p>
* In addition the the [error codes](http://www.jsonrpc.org/specification#error_object) specified in
* the JSON-RPC spec, we use the following application specific error codes:
*
* <pre>
* code | message | meaning
* ---- | ------- | -------
* 100 | Feature is disabled | The operation is unable to complete because a feature is disabled
* 101 | VM must be paused | This operation is only valid when the VM is paused
* 102 | Cannot add breakpoint | The VM is unable to add a breakpoint at the specified line or function
* 103 | Stream already subscribed | The client is already subscribed to the specified _streamId_
* 104 | Stream not subscribed | The client is not subscribed to the specified _streamId_
* </pre>
*/
public class RPCError extends Element implements VmServiceConst {
/**
* The response code used by the client when it receives a response from the server that it did
* not expect. For example, it requested a library element but received a list.
*/
public static final int UNEXPECTED_RESPONSE = 5;
public static RPCError unexpected(String expectedType, Response response) {
String errMsg = "Expected type " + expectedType + " but received " + response.getType();
if (response instanceof Sentinel) {
errMsg += ": " + ((Sentinel) response).getKind();
}
JsonObject json = new JsonObject();
json.addProperty("code", UNEXPECTED_RESPONSE);
json.addProperty("message", errMsg);
JsonObject data = new JsonObject();
data.addProperty("details", errMsg);
data.add("response", response.getJson());
json.add("data", data);
return new RPCError(json);
}
public RPCError(JsonObject json) {
super(json);
}
public int getCode() {
return json.get("code").getAsInt();
}
public String getDetails() {
JsonElement data = json.get("data");
if (data instanceof JsonObject) {
JsonElement details = ((JsonObject) data).get("details");
if (details != null) {
return details.getAsString();
}
}
return null;
}
public String getMessage() {
return json.get("message").getAsString();
}
public JsonObject getRequest() {
JsonElement data = json.get("data");
if (data instanceof JsonObject) {
JsonElement request = ((JsonObject) data).get("request");
if (request instanceof JsonObject) {
return (JsonObject) request;
}
}
return null;
}
}

View file

@ -1,81 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
import com.google.common.collect.Lists;
import com.google.gson.JsonObject;
import java.util.LinkedList;
/**
* A {@link RequestSink} that enqueues all requests and can be later converted into a "passthrough"
* or an "error" {@link RequestSink}.
*/
public class BlockingRequestSink implements RequestSink {
/**
* The base {@link RequestSink}
*/
private final RequestSink base;
/**
* A queue of requests.
*/
private final LinkedList<JsonObject> queue = Lists.newLinkedList();
public BlockingRequestSink(RequestSink base) {
this.base = base;
}
@Override
public void add(JsonObject request) {
synchronized (queue) {
queue.add(request);
}
}
@Override
public void close() {
base.close();
}
/**
* Responds with an error to all the currently queued requests and return a {@link RequestSink} to
* do the same for all the future requests.
*
* @param errorResponseSink the sink to send error responses to, not {@code null}
*/
public RequestSink toErrorSink(ResponseSink errorResponseSink, String errorResponseCode,
String errorResponseMessage) {
ErrorRequestSink errorRequestSink = new ErrorRequestSink(errorResponseSink, errorResponseCode,
errorResponseMessage);
synchronized (queue) {
for (JsonObject request : queue) {
errorRequestSink.add(request);
}
}
return errorRequestSink;
}
/**
* Returns the passthrough {@link RequestSink}.
*/
public RequestSink toPassthroughSink() {
synchronized (queue) {
for (JsonObject request : queue) {
base.add(request);
}
}
return base;
}
}

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
import com.google.gson.JsonObject;
import org.dartlang.vm.service.logging.Logging;
/**
* A {@link RequestSink} that reports with an error to each request.
*/
public class ErrorRequestSink implements RequestSink, VmServiceConst {
/**
* The {@link ResponseSink} to send error responses to.
*/
private final ResponseSink responseSink;
private final String code;
private final String message;
public ErrorRequestSink(ResponseSink responseSink, String code, String message) {
if (responseSink == null || code == null || message == null) {
throw new IllegalArgumentException("Unexpected null argument: " + responseSink + " "
+ code + " " + message);
}
this.responseSink = responseSink;
this.code = code;
this.message = message;
}
@Override
public void add(JsonObject request) {
String id = request.getAsJsonPrimitive(ID).getAsString();
try {
// TODO(danrubel) is this the correct format for an error response?
JsonObject error = new JsonObject();
error.addProperty(CODE, code);
error.addProperty(MESSAGE, message);
JsonObject response = new JsonObject();
response.addProperty(ID, id);
response.add(ERROR, error);
responseSink.add(response);
} catch (Throwable e) {
Logging.getLogger().logError(e.getMessage(), e);
}
}
@Override
public void close() {
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
import com.google.gson.JsonObject;
/**
* A destination for observatory requests.
*/
public interface RequestSink {
/**
* Put request into the sink.
*
* @param request the request to put, not {@code null}.
*/
void add(JsonObject request);
/**
* Close the communication channel.
*/
void close();
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
import com.google.gson.JsonObject;
/**
* A destination for responses.
*/
public interface ResponseSink {
/**
* Put response into the sink.
*
* @param response the response to put, not {@code null}.
*/
void add(JsonObject response) throws Exception;
}

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
/**
* JSON constants used when communicating with the VM observatory service.
*/
public interface VmServiceConst {
static final String CODE = "code";
static final String ERROR = "error";
static final String EVENT = "event";
static final String ID = "id";
static final String MESSAGE = "message";
static final String METHOD = "method";
static final String PARAMS = "params";
static final String RESULT = "result";
static final String STREAM_ID = "streamId";
static final String TYPE = "type";
static final String JSONRPC = "jsonrpc";
static final String JSONRPC_VERSION = "2.0";
static final String DATA = "data";
/**
* Parse error Invalid JSON was received by the server.
* An error occurred on the server while parsing the JSON text.
*/
static final int PARSE_ERROR = -32700;
/**
* Invalid Request The JSON sent is not a valid Request object.
*/
static final int INVALID_REQUEST = -32600;
/**
* Method not found The method does not exist / is not available.
*/
static final int METHOD_NOT_FOUND = -32601;
/**
* Invalid params Invalid method parameter(s).
*/
static final int INVALID_PARAMS = -32602;
/**
* Server error Reserved for implementation-defined server-errors.
* -32000 to -32099
*/
static final int SERVER_ERROR = -32000;
}

View file

@ -1,58 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.internal;
import com.google.gson.JsonObject;
import de.roderick.weberknecht.WebSocket;
import de.roderick.weberknecht.WebSocketException;
import org.dartlang.vm.service.logging.Logging;
/**
* An {@link WebSocket} based implementation of {@link RequestSink}.
*/
public class WebSocketRequestSink implements RequestSink {
private WebSocket webSocket;
public WebSocketRequestSink(WebSocket webSocket) {
this.webSocket = webSocket;
}
@Override
public void add(JsonObject json) {
String request = json.toString();
if (webSocket == null) {
Logging.getLogger().logInformation("Dropped: " + request);
return;
}
Logging.getLogger().logInformation("Sent: " + request);
try {
webSocket.send(request);
} catch (WebSocketException e) {
Logging.getLogger().logError("Failed to send request: " + request, e);
}
}
@Override
public void close() {
if (webSocket != null) {
try {
webSocket.close();
} catch (WebSocketException e) {
Logging.getLogger().logError("Failed to close websocket", e);
}
webSocket = null;
}
}
}

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.logging;
/**
* The interface {@code Logger} defines the behavior of objects that can be used to receive
* information about errors. Implementations usually write this information to a file, but can also
* record the information for later use (such as during testing) or even ignore the information.
*/
public interface Logger {
/**
* Implementation of {@link Logger} that does nothing.
*/
class NullLogger implements Logger {
@Override
public void logError(String message) {
}
@Override
public void logError(String message, Throwable exception) {
}
@Override
public void logInformation(String message) {
}
@Override
public void logInformation(String message, Throwable exception) {
}
}
static final Logger NULL = new NullLogger();
/**
* Log the given message as an error.
*
* @param message an explanation of why the error occurred or what it means
*/
void logError(String message);
/**
* Log the given exception as one representing an error.
*
* @param message an explanation of why the error occurred or what it means
* @param exception the exception being logged
*/
void logError(String message, Throwable exception);
/**
* Log the given informational message.
*
* @param message an explanation of why the error occurred or what it means
*/
void logInformation(String message);
/**
* Log the given exception as one representing an informational message.
*
* @param message an explanation of why the error occurred or what it means
* @param exception the exception being logged
*/
void logInformation(String message, Throwable exception);
}

View file

@ -1,30 +0,0 @@
/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service.logging;
/**
* {@code Logging} provides a global instance of {@link Logger}.
*/
public class Logging {
private static Logger logger = Logger.NULL;
public static Logger getLogger() {
return logger;
}
public static void setLogger(Logger logger) {
Logging.logger = logger == null ? Logger.NULL : logger;
}
}

View file

@ -1,214 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import org.dartlang.vm.service.consumer.GetInstanceConsumer;
import org.dartlang.vm.service.element.BoundField;
import org.dartlang.vm.service.element.ClassRef;
import org.dartlang.vm.service.element.Instance;
import org.dartlang.vm.service.element.InstanceKind;
import org.dartlang.vm.service.element.InstanceRef;
import org.dartlang.vm.service.element.Isolate;
import org.dartlang.vm.service.element.RPCError;
/**
* Utility class for converting {@link InstanceRef} to a human readable string.
*/
public class InstanceRefToString {
private Isolate isolate;
private final VmService service;
private final OpLatch masterLatch;
/**
* Construct a new instance for converting one or more {@link InstanceRef} to human readable
* strings. Specify an {@link OpLatch} so that this class can update the expiration time for any
* waiting thread as it makes {@link VmService} class to obtain details about each
* {@link InstanceRef}.
*/
public InstanceRefToString(Isolate isolate, VmService service, OpLatch latch) {
this.isolate = isolate;
this.service = service;
this.masterLatch = latch;
}
/**
* Return a human readable string for the given {@link InstanceRef}.
*/
public String toString(InstanceRef ref) {
StringBuilder result = new StringBuilder();
printInstance(result, ref, 4);
return result.toString();
}
/**
* Request the instance information from the {@link VmService}.
*
* @param ref the instance reference (not {@code null})
* @return the instance or {@code null} if there was a problem.
*/
private Instance getInstance(InstanceRef ref) {
// Request master latch extend its timeout because we are making another call to VmService
masterLatch.opWorking();
final ResultLatch<Instance> instLatch = new ResultLatch<Instance>();
service.getInstance(isolate.getId(), ref.getId(), new GetInstanceConsumer() {
@Override
public void onError(RPCError error) {
instLatch.setValue(null);
}
@Override
public void received(Instance instance) {
instLatch.setValue(instance);
}
});
return instLatch.getValue();
}
/**
* Convert the given {@link InstanceRef} into a human readable string.
*
* @param result the buffer to which the human readable string is added
* @param ref the instance to be converted (not {@code null})
* @param maxDepth the maximum number of recursions this method can make on itself to determine
* human readable strings for child objects
*/
private void printInstance(StringBuilder result, InstanceRef ref, int maxDepth) {
if (ref == null) {
result.append("-- no value --");
return;
}
InstanceKind kind = ref.getKind();
if (kind == null) {
result.append("-- unknown instance kind --");
return;
}
switch (kind) {
case Bool:
case Double:
case Float32x4:
case Float64x2:
case Int:
case Int32x4:
case Null:
case StackTrace:
result.append(ref.getValueAsString());
return;
case String:
result.append("'");
// Should escape chars such as newline before printing
result.append(ref.getValueAsString());
if (ref.getValueAsStringIsTruncated()) {
result.append("...");
}
result.append("'");
return;
case List:
printList(result, ref, maxDepth);
return;
case PlainInstance:
printPlainInstance(result, ref, maxDepth);
return;
case BoundedType:
case Closure:
case Float32List:
case Float32x4List:
case Float64List:
case Float64x2List:
case Int16List:
case Int32List:
case Int32x4List:
case Int64List:
case Int8List:
case Map:
case MirrorReference:
case RegExp:
case Type:
case TypeParameter:
case TypeRef:
case Uint16List:
case Uint32List:
case Uint64List:
case Uint8ClampedList:
case Uint8List:
case WeakProperty:
}
result.append("a " + kind);
}
/**
* Convert the given list into a human readable string.
*
* @param result the buffer to which the human readable string is added
* @param ref an instance reference of type "List" (not {@code null})
* @param maxDepth the maximum number of recursions this method can make on itself to determine
* human readable strings for child objects
*/
private void printList(StringBuilder result, InstanceRef ref, int maxDepth) {
if (maxDepth == 0) {
result.append("a List");
return;
}
result.append("[");
Instance list = getInstance(ref);
if (list == null) {
result.append("?error?]");
return;
}
int count = 0;
for (InstanceRef elem : list.getElements()) {
if (count > 10) {
result.append(", ...");
break;
}
if (count > 0) {
result.append(", ");
}
++count;
printInstance(result, elem, maxDepth - 1);
}
result.append("]");
}
/**
* Convert the given instance into a human readable string.
*
* @param result the buffer to which the human readable string is added
* @param ref an instance reference of type "PlainInstance" (not {@code null})
* @param maxDepth the maximum number of recursions this method can make on itself to determine
* human readable strings for child objects
*/
private void printPlainInstance(StringBuilder result, InstanceRef ref, int maxDepth) {
ClassRef classRef = ref.getClassRef();
String className = classRef.getName();
if (maxDepth == 0) {
result.append("a " + className);
return;
}
result.append(className);
result.append("(");
Instance inst = getInstance(ref);
boolean first = true;
for (BoundField field : inst.getFields()) {
if (first) {
first = false;
} else {
result.append(", ");
}
printInstance(result, field.getValue(), maxDepth - 1);
}
result.append(")");
}
}

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* {@link OpLatch} is used by one thread to wait for another thread to complete (see
* {@link OpLatch#waitOpComplete()} and {@link OpLatch#waitAndAssertOpComplete()}). If the operation
* does not complete before the expiration time then {@link OpLatch#waitOpComplete()} returns
* {@code false} and {@link OpLatch#waitAndAssertOpComplete()} throws an exception.
*/
class OpLatch {
final CountDownLatch latch = new CountDownLatch(1);
private long endTime;
/**
* Set or increase the time after which the operation is considered failed. This is automatically
* called by {@link #waitAndAssertOp()} and {@link #waitOpComplete()}.
*/
public void opWorking() {
endTime = System.currentTimeMillis() + 5000;
}
/**
* Call to indicate that the operation completed successfully.
*/
void opComplete() {
latch.countDown();
}
/**
* Wait for the operation to complete or the time limit to expire. Periodically call
* {@link #opWorking()} to increase the expiration time. Throw a {@link RuntimeException} if the
* operation did not complete before the expiration time.
*/
void waitAndAssertOpComplete() {
if (!waitOpComplete()) {
System.out.println(">>> No response received");
throw new RuntimeException("No response received");
}
}
/**
* Wait for the operation to complete or the time limit to expire. Periodically call
* {@link #opWorking()} to increase the expiration time.
*
* @return {@code true} if the operation completed, or {@code false} otherwise
*/
boolean waitOpComplete() {
opWorking();
while (true) {
long waitTimeMillis = endTime - System.currentTimeMillis();
if (waitTimeMillis <= 0) {
return latch.getCount() == 0;
}
try {
if (latch.await(waitTimeMillis, TimeUnit.MILLISECONDS)) {
return true;
}
} catch (InterruptedException e) {
// ignore and loop to check if timeout has changed
}
}
}
}

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
/**
* {@link ResultLatch} is used by one thread to communicate a result to another thread.
*/
public class ResultLatch<T> extends OpLatch {
private T value;
public T getValue() {
waitAndAssertOpComplete();
return value;
}
public void setValue(T value) {
this.value = value;
opComplete();
}
}

View file

@ -1,93 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import com.google.common.base.Charsets;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Echo the content of a stream to {@link System.out} with the given prefix.
*/
public class SampleOutPrinter {
private class LinesReaderThread extends Thread {
public LinesReaderThread() {
setName("SampleOutPrinter.LinesReaderThread - " + prefix);
setDaemon(true);
}
@Override
public void run() {
while (true) {
String line;
try {
line = reader.readLine();
} catch (IOException e) {
System.out.println("Exception reading sample stream");
e.printStackTrace();
return;
}
// check for EOF
if (line == null) {
return;
}
synchronized (currentLineLock) {
currentLine = line;
currentLineLock.notifyAll();
}
System.out.println("[" + prefix + "] " + line);
}
}
}
private String currentLine;
private final Object currentLineLock = new Object();
private final String prefix;
private final BufferedReader reader;
public SampleOutPrinter(String prefix, InputStream stream) {
this.prefix = prefix;
this.reader = new BufferedReader(new InputStreamReader(stream, Charsets.UTF_8));
new LinesReaderThread().start();
}
public void assertEmpty() {
synchronized (currentLineLock) {
if (currentLine != null) {
throw new RuntimeException("Did not expect " + prefix + ": \"" + currentLine + "\"");
}
}
}
public void assertLastLine(String text) {
synchronized (currentLineLock) {
if (text == null) {
if (currentLine != null) {
throw new RuntimeException("Did not expect " + prefix + ": \"" + currentLine + "\"");
}
} else {
if (currentLine == null || !currentLine.contains(text)) {
throw new RuntimeException("Expected current line to contain text\n"
+ "\nexpected: [" + text + "]"
+ "\nactual: [" + currentLine + "]");
}
}
}
}
}

View file

@ -1,86 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import org.dartlang.vm.service.element.Event;
import org.dartlang.vm.service.element.EventKind;
import java.util.Set;
/**
* Sample VmListener for responding to state changes in the running application
*/
public class SampleVmServiceListener implements VmServiceListener {
private final Object lock = new Object();
private String lastStreamId;
private Event lastEvent;
private final Set<EventKind> ignoreAll;
SampleVmServiceListener(Set<EventKind> ignoreAll) {
this.ignoreAll = ignoreAll;
}
@Override
public void connectionOpened() {
}
@Override
public void received(String streamId, Event event) {
synchronized (lock) {
if (ignoreAll.contains(event.getKind())) {
return;
}
if (lastStreamId != null) {
unexpectedEvent(lastStreamId, lastEvent);
}
lastStreamId = streamId;
lastEvent = event;
lock.notifyAll();
}
}
@Override
public void connectionClosed() {
}
public Event waitFor(String expectedStreamId, EventKind expectedEventKind) {
long end = System.currentTimeMillis() + 5000;
synchronized (lock) {
while (true) {
if (expectedStreamId.equals(lastStreamId) && expectedEventKind.equals(lastEvent.getKind())) {
Event event = lastEvent;
lastStreamId = null;
lastEvent = null;
return event;
}
long timeout = end - System.currentTimeMillis();
if (timeout <= 0) {
break;
}
try {
lock.wait(timeout);
} catch (InterruptedException e) {
// ignored
}
}
}
throw new RuntimeException("Expected event: " + expectedStreamId + ", " + expectedEventKind);
}
private void unexpectedEvent(String streamId, Event event) {
System.out.println("****** Unexpected Event: " + streamId + ", " + event.getKind());
}
}

View file

@ -1,661 +0,0 @@
/*
* Copyright (c) 2015, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.dartlang.vm.service;
import com.google.gson.JsonObject;
import org.dartlang.vm.service.consumer.*;
import org.dartlang.vm.service.element.*;
import org.dartlang.vm.service.logging.Logger;
import org.dartlang.vm.service.logging.Logging;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
public class VmServiceTest {
private static File dartVm;
private static File sampleDart;
private static File sampleDartWithException;
private static int vmPort = 7575;
private static Process process;
private static VmService vmService;
private static SampleOutPrinter sampleOut;
private static SampleOutPrinter sampleErr;
private static int actualVmServiceVersionMajor;
public static void main(String[] args) {
setupLogging();
parseArgs(args);
try {
echoDartVmVersion();
runSample();
runSampleWithException();
System.out.println("Test Complete");
} finally {
vmDisconnect();
stopSample();
}
}
private static void echoDartVmVersion() {
// Echo Dart VM version
List<String> processArgs = new ArrayList<>();
processArgs.add(dartVm.getAbsolutePath());
processArgs.add("--version");
ProcessBuilder processBuilder = new ProcessBuilder(processArgs);
try {
process = processBuilder.start();
} catch (IOException e) {
throw new RuntimeException("Failed to launch Dart VM", e);
}
new SampleOutPrinter("version output", process.getInputStream());
new SampleOutPrinter("version output", process.getErrorStream());
}
private static void finishExecution(SampleVmServiceListener vmListener, ElementList<IsolateRef> isolates) {
// Finish execution
vmResume(isolates.get(0), null);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.Resume);
// VM pauses on exit and must be resumed to cleanly terminate process
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.PauseExit);
vmResume(isolates.get(0), null);
vmListener.waitFor(VmService.ISOLATE_STREAM_ID, EventKind.IsolateExit);
waitForProcessExit();
sampleOut.assertLastLine("exiting");
// TODO(devoncarew):
// vm-service: isolate(544050040) 'sample_main.dart:main()' has no debugger attached and is paused at start.
//sampleErr.assertLastLine(null);
process = null;
}
private static boolean isWindows() {
return System.getProperty("os.name").startsWith("Win");
}
private static void parseArgs(String[] args) {
if (args.length != 1) {
showErrorAndExit("Expected absolute path to Dart SDK");
}
File sdkDir = new File(args[0]);
if (!sdkDir.isDirectory()) {
showErrorAndExit("Specified directory does not exist: " + sdkDir);
}
File binDir = new File(sdkDir, "bin");
dartVm = new File(binDir, isWindows() ? "dart.exe" : "dart");
if (!dartVm.isFile()) {
showErrorAndExit("Cannot find Dart VM in SDK: " + dartVm);
}
File currentDir = new File(".").getAbsoluteFile();
File projDir = currentDir;
String projName = "vm_service";
while (!projDir.getName().equals(projName)) {
projDir = projDir.getParentFile();
if (projDir == null) {
showErrorAndExit("Cannot find project " + projName + " from " + currentDir);
return;
}
}
sampleDart = new File(projDir, "java/example/sample_main.dart".replace("/", File.separator));
if (!sampleDart.isFile()) {
showErrorAndExit("Cannot find sample: " + sampleDart);
}
sampleDartWithException = new File(projDir,
"java/example/sample_exception.dart".replace("/", File.separator));
if (!sampleDartWithException.isFile()) {
showErrorAndExit("Cannot find sample: " + sampleDartWithException);
}
System.out.println("Using Dart SDK: " + sdkDir);
}
/**
* Exercise VM service with "normal" sample.
*/
private static void runSample() {
SampleVmServiceListener vmListener = startSampleAndConnect(sampleDart);
vmGetVersion();
ElementList<IsolateRef> isolates = vmGetVmIsolates();
Isolate sampleIsolate = vmGetIsolate(isolates.get(0));
Library rootLib = vmGetLibrary(sampleIsolate, sampleIsolate.getRootLib());
vmGetScript(sampleIsolate, rootLib.getScripts().get(0));
vmCallServiceExtension(sampleIsolate);
// Run to breakpoint on line "foo(1);"
vmAddBreakpoint(sampleIsolate, rootLib.getScripts().get(0), 25);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.BreakpointAdded);
vmResume(isolates.get(0), null);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.Resume);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.PauseBreakpoint);
sampleOut.assertLastLine("hello");
// Get stack trace
vmGetStack(sampleIsolate);
// Evaluate
vmEvaluateInFrame(sampleIsolate, 0, "deepList[0]");
// Get coverage information
vmGetSourceReport(sampleIsolate);
// Step over line "foo(1);"
vmResume(isolates.get(0), StepOption.Over);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.Resume);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.PauseBreakpoint);
sampleOut.assertLastLine("val: 1");
finishExecution(vmListener, isolates);
}
/**
* Exercise VM service with sample that throws exceptions.
*/
private static void runSampleWithException() {
SampleVmServiceListener vmListener = startSampleAndConnect(sampleDartWithException);
ElementList<IsolateRef> isolates = vmGetVmIsolates();
Isolate sampleIsolate = vmGetIsolate(isolates.get(0));
// Run until exception occurs
vmPauseOnException(isolates.get(0), ExceptionPauseMode.All);
vmResume(isolates.get(0), null);
vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.Resume);
Event event = vmListener.waitFor(VmService.DEBUG_STREAM_ID, EventKind.PauseException);
InstanceRefToString convert = new InstanceRefToString(sampleIsolate, vmService, new OpLatch());
System.out.println("Received PauseException event");
System.out.println(" Exception: " + convert.toString(event.getException()));
System.out.println(" Top Frame:");
showFrame(convert, event.getTopFrame());
sampleOut.assertLastLine("hello");
finishExecution(vmListener, isolates);
}
private static void setupLogging() {
Logging.setLogger(new Logger() {
@Override
public void logError(String message) {
System.out.println("Log error: " + message);
}
@Override
public void logError(String message, Throwable exception) {
System.out.println("Log error: " + message);
if (exception != null) {
System.out.println("Log error exception: " + exception);
exception.printStackTrace();
}
}
@Override
public void logInformation(String message) {
System.out.println("Log info: " + message);
}
@Override
public void logInformation(String message, Throwable exception) {
System.out.println("Log info: " + message);
if (exception != null) {
System.out.println("Log info exception: " + exception);
exception.printStackTrace();
}
}
});
}
private static void showErrorAndExit(String errMsg) {
System.out.println(errMsg);
System.out.flush();
sleep(10);
System.out.println("Usage: VmServiceTest /path/to/Dart/SDK");
System.exit(1);
}
private static void showFrame(InstanceRefToString convert, Frame frame) {
System.out.println(" #" + frame.getIndex() + " " + frame.getFunction().getName() + " ("
+ frame.getLocation().getScript().getUri() + ")");
for (BoundVariable var : frame.getVars()) {
InstanceRef instanceRef = (InstanceRef)var.getValue();
System.out.println(" " + var.getName() + " = " + convert.toString(instanceRef));
}
}
private static void showRPCError(RPCError error) {
System.out.println(">>> Received error response");
System.out.println(" Code: " + error.getCode());
System.out.println(" Message: " + error.getMessage());
System.out.println(" Details: " + error.getDetails());
System.out.println(" Request: " + error.getRequest());
}
private static void showSentinel(Sentinel sentinel) {
System.out.println(">>> Received sentinel response");
System.out.println(" Sentinel kind: " + sentinel.getKind());
System.out.println(" Sentinel value: " + sentinel.getValueAsString());
}
private static void sleep(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// ignored
}
}
private static void startSample(File dartFile) {
List<String> processArgs;
ProcessBuilder processBuilder;
// Use new port to prevent race conditions
// between one sample releasing a port
// and the next sample using it.
++vmPort;
processArgs = new ArrayList<>();
processArgs.add(dartVm.getAbsolutePath());
processArgs.add("--pause_isolates_on_start");
processArgs.add("--observe");
processArgs.add("--enable-vm-service=" + vmPort);
processArgs.add("--disable-service-auth-codes");
processArgs.add(dartFile.getAbsolutePath());
processBuilder = new ProcessBuilder(processArgs);
System.out.println("=================================================");
System.out.println("Launching sample: " + dartFile);
try {
process = processBuilder.start();
} catch (IOException e) {
throw new RuntimeException("Failed to launch Dart sample", e);
}
// Echo sample application output to System.out
sampleOut = new SampleOutPrinter("stdout", process.getInputStream());
sampleErr = new SampleOutPrinter("stderr", process.getErrorStream());
System.out.println("Dart process started - port " + vmPort);
}
private static SampleVmServiceListener startSampleAndConnect(File dartFile) {
startSample(dartFile);
sleep(1000);
vmConnect();
SampleVmServiceListener vmListener = new SampleVmServiceListener(
new HashSet<>(Collections.singletonList(EventKind.BreakpointResolved)));
vmService.addVmServiceListener(vmListener);
vmStreamListen(VmService.DEBUG_STREAM_ID);
vmStreamListen(VmService.ISOLATE_STREAM_ID);
return vmListener;
}
private static void stopSample() {
if (process == null) {
return;
}
final Process processToStop = process;
process = null;
long endTime = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < endTime) {
try {
int exit = processToStop.exitValue();
if (exit != 0) {
System.out.println("Sample exit code: " + exit);
}
return;
} catch (IllegalThreadStateException e) {
//$FALL-THROUGH$
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
//$FALL-THROUGH$
}
}
processToStop.destroy();
System.out.println("Terminated sample process");
}
@SuppressWarnings("SameParameterValue")
private static void vmAddBreakpoint(Isolate isolate, ScriptRef script, int lineNum) {
final OpLatch latch = new OpLatch();
vmService.addBreakpoint(isolate.getId(), script.getId(), lineNum, new BreakpointConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Breakpoint response) {
System.out.println("Received Breakpoint response");
System.out.println(" BreakpointNumber:" + response.getBreakpointNumber());
latch.opComplete();
}
});
latch.waitAndAssertOpComplete();
}
private static void vmConnect() {
try {
vmService = VmService.localConnect(vmPort);
} catch (IOException e) {
throw new RuntimeException("Failed to connect to the VM vmService service", e);
}
}
private static void vmDisconnect() {
if (vmService != null) {
vmService.disconnect();
}
}
@SuppressWarnings("SameParameterValue")
private static void vmEvaluateInFrame(Isolate isolate, int frameIndex, String expression) {
System.out.println("Evaluating: " + expression);
final ResultLatch<InstanceRef> latch = new ResultLatch<>();
vmService.evaluateInFrame(isolate.getId(), frameIndex, expression, new EvaluateInFrameConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(ErrorRef response) {
showErrorAndExit(response.getMessage());
}
public void received(Sentinel response) {
System.out.println(response.getValueAsString());
}
@Override
public void received(InstanceRef response) {
System.out.println("Received InstanceRef response");
System.out.println(" Id: " + response.getId());
System.out.println(" Kind: " + response.getKind());
System.out.println(" Json: " + response.getJson());
latch.setValue(response);
}
});
InstanceRef instanceRef = latch.getValue();
InstanceRefToString convert = new InstanceRefToString(isolate, vmService, latch);
System.out.println("Result: " + convert.toString(instanceRef));
}
private static SourceReport vmGetSourceReport(Isolate isolate) {
System.out.println("Getting coverage information for " + isolate.getId());
final long startTime = System.currentTimeMillis();
final ResultLatch<SourceReport> latch = new ResultLatch<>();
vmService.getSourceReport(isolate.getId(), Collections.singletonList(SourceReportKind.Coverage), new SourceReportConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(SourceReport response) {
System.out.println("Received SourceReport response (" + (System.currentTimeMillis() - startTime) + "ms)");
System.out.println(" Script count: " + response.getScripts().size());
System.out.println(" Range count: " + response.getRanges().size());
latch.setValue(response);
}
});
return latch.getValue();
}
private static Isolate vmGetIsolate(IsolateRef isolate) {
final ResultLatch<Isolate> latch = new ResultLatch<>();
vmService.getIsolate(isolate.getId(), new GetIsolateConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Isolate response) {
System.out.println("Received Isolate response");
System.out.println(" Id: " + response.getId());
System.out.println(" Name: " + response.getName());
System.out.println(" Number: " + response.getNumber());
System.out.println(" Start Time: " + response.getStartTime());
System.out.println(" RootLib Id: " + response.getRootLib().getId());
System.out.println(" RootLib Uri: " + response.getRootLib().getUri());
System.out.println(" RootLib Name: " + response.getRootLib().getName());
System.out.println(" RootLib Json: " + response.getRootLib().getJson());
System.out.println(" Isolate: " + response);
latch.setValue(response);
}
@Override
public void received(Sentinel response) {
showSentinel(response);
}
});
return latch.getValue();
}
private static Library vmGetLibrary(Isolate isolateId, LibraryRef library) {
final ResultLatch<Library> latch = new ResultLatch<>();
vmService.getLibrary(isolateId.getId(), library.getId(), new GetLibraryConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Library response) {
System.out.println("Received GetLibrary library");
System.out.println(" uri: " + response.getUri());
latch.setValue(response);
}
});
return latch.getValue();
}
private static void vmGetScript(Isolate isolate, ScriptRef scriptRef) {
final ResultLatch<Script> latch = new ResultLatch<>();
vmService.getObject(isolate.getId(), scriptRef.getId(), new GetObjectConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Obj response) {
if (response instanceof Script) {
latch.setValue((Script) response);
} else {
RPCError.unexpected("Script", response);
}
}
@Override
public void received(Sentinel response) {
RPCError.unexpected("Script", response);
}
});
Script script = latch.getValue();
System.out.println("Received Script");
System.out.println(" Id: " + script.getId());
System.out.println(" Uri: " + script.getUri());
System.out.println(" Source: " + script.getSource());
System.out.println(" TokenPosTable: " + script.getTokenPosTable());
if (script.getTokenPosTable() == null) {
showErrorAndExit("Expected TokenPosTable to be non-null");
}
}
private static void vmGetStack(Isolate isolate) {
final ResultLatch<Stack> latch = new ResultLatch<>();
vmService.getStack(isolate.getId(), new StackConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Stack stack) {
latch.setValue(stack);
}
});
Stack stack = latch.getValue();
System.out.println("Received Stack response");
System.out.println(" Messages:");
for (Message message : stack.getMessages()) {
System.out.println(" " + message.getName());
}
System.out.println(" Frames:");
InstanceRefToString convert = new InstanceRefToString(isolate, vmService, latch);
for (Frame frame : stack.getFrames()) {
showFrame(convert, frame);
}
}
private static void vmGetVersion() {
final OpLatch latch = new OpLatch();
vmService.getVersion(new VersionConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Version response) {
System.out.println("Received Version response");
actualVmServiceVersionMajor = response.getMajor();
System.out.println(" Major: " + actualVmServiceVersionMajor);
System.out.println(" Minor: " + response.getMinor());
System.out.println(response.getJson());
latch.opComplete();
}
});
latch.waitAndAssertOpComplete();
}
private static void vmCallServiceExtension(Isolate isolateId) {
final OpLatch latch = new OpLatch();
vmService.callServiceExtension(isolateId.getId(), "getIsolate", new ServiceExtensionConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(JsonObject result) {
System.out.println("Received response: " + result);
latch.opComplete();
}
});
latch.waitAndAssertOpComplete();
}
private static ElementList<IsolateRef> vmGetVmIsolates() {
final ResultLatch<ElementList<IsolateRef>> latch = new ResultLatch<>();
vmService.getVM(new VMConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(VM response) {
System.out.println("Received VM response");
System.out.println(" ArchitectureBits: " + response.getArchitectureBits());
System.out.println(" HostCPU: " + response.getHostCPU());
System.out.println(" TargetCPU: " + response.getTargetCPU());
System.out.println(" Pid: " + response.getPid());
System.out.println(" StartTime: " + response.getStartTime());
for (IsolateRef isolate : response.getIsolates()) {
System.out.println(" Isolate " + isolate.getNumber() + ", " + isolate.getId() + ", "
+ isolate.getName());
}
latch.setValue(response.getIsolates());
}
});
return latch.getValue();
}
private static void vmPauseOnException(IsolateRef isolate, ExceptionPauseMode mode) {
System.out.println("Request pause on exception: " + mode);
final OpLatch latch = new OpLatch();
vmService.setExceptionPauseMode(isolate.getId(), mode, new SuccessConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Success response) {
System.out.println("Successfully set pause on exception");
latch.opComplete();
}
});
latch.waitAndAssertOpComplete();
}
private static void vmResume(IsolateRef isolateRef, final StepOption step) {
final String id = isolateRef.getId();
vmService.resume(id, step, null, new SuccessConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Success response) {
if (step == null) {
System.out.println("Resumed isolate " + id);
} else {
System.out.println("Step " + step + " isolate " + id);
}
}
});
// Do not wait for confirmation, but display error if it occurs
}
private static void vmStreamListen(String streamId) {
final OpLatch latch = new OpLatch();
vmService.streamListen(streamId, new SuccessConsumer() {
@Override
public void onError(RPCError error) {
showRPCError(error);
}
@Override
public void received(Success response) {
System.out.println("Subscribed to debug event stream");
latch.opComplete();
}
});
latch.waitAndAssertOpComplete();
}
private static void waitForProcessExit() {
if (actualVmServiceVersionMajor == 2) {
// Don't wait for VM 1.12 - protocol 2.1
return;
}
long end = System.currentTimeMillis() + 5000;
while (true) {
try {
System.out.println("Exit code: " + process.exitValue());
return;
} catch (IllegalThreadStateException e) {
// fall through to wait for exit
}
if (System.currentTimeMillis() >= end) {
throw new RuntimeException("Expected child process to finish");
}
sleep(10);
}
}
}

View file

@ -1,15 +0,0 @@
From https://github.com/google/gson/blob/master/LICENSE
Copyright 2008 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,204 +0,0 @@
From https://github.com/google/guava/blob/master/COPYING
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,15 +0,0 @@
From https://github.com/pelotoncycle/weberknecht/blob/master/src/de/roderick/weberknecht/WebSocket.java
Copyright (C) 2012 Roderick Baier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1 +0,0 @@
version=3.22

View file

@ -1,64 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import '../vm_service.dart';
class IsolateHelper {
static HeapSpace getNewSpace(Isolate isolate) {
Map m = isolate.json['_heaps']['new'];
return HeapSpace.parse(m);
}
static HeapSpace getOldSpace(Isolate isolate) {
Map m = isolate.json['_heaps']['old'];
return HeapSpace.parse(m);
}
static List<TagCounter> getTagCounters(Isolate isolate) {
Map m = isolate.json['_tagCounters'];
List<String> names = m['names'];
List<int> counters = m['counters'];
List<TagCounter> result = [];
for (int i = 0; i < counters.length; i++) {
result.add(new TagCounter(names[i], counters[i]));
}
return result;
}
}
class AllocationProfileHelper {
static HeapSpace getNewSpace(AllocationProfile profile) {
return HeapSpace.parse(profile.json['heaps']['new']);
}
static HeapSpace getOldSpace(AllocationProfile profile) {
return HeapSpace.parse(profile.json['heaps']['old']);
}
}
class GcEventHelper {
static String reason(Event event) => event.json['reason'];
static HeapSpace getNewSpace(Event event) {
return HeapSpace.parse(event.json['new']);
}
static HeapSpace getOldSpace(Event event) {
return HeapSpace.parse(event.json['old']);
}
}
class TagCounter {
final String name;
final int count;
TagCounter(this.name, this.count);
}
//class GraphEventHelper {
// // int chunkIndex
// // int chunkCount
// // int nodeCount
//}

View file

@ -1,68 +0,0 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'stream_helpers.dart';
import '../vm_service.dart' show VmServerConnection, RPCError, Event, EventKind;
/// A registry of custom service extensions to [VmServerConnection]s in which
/// they were registered.
class ServiceExtensionRegistry {
/// Maps service extensions registered through the protocol to the
/// [VmServerConnection] in which they were registered.
///
/// Note: this does not track services registered through `dart:developer`,
/// only the services registered through the `_registerService` rpc method.
final _extensionToConnection = <String, VmServerConnection>{};
/// Controller for tracking registration and unregistration events.
final _eventController = StreamController<Event>.broadcast();
ServiceExtensionRegistry();
/// Registers [extension] for [client].
///
/// All future requests for [extension] will be routed to [client].
void registerExtension(String extension, VmServerConnection client) {
if (_extensionToConnection.containsKey(extension)) {
throw RPCError('registerExtension', 111, 'Service already registered');
}
_eventController.sink.add(_toRegistrationEvent(extension));
_extensionToConnection[extension] = client;
// Remove the mapping if the client disconnects.
client.done.whenComplete(() {
_extensionToConnection.remove(extension);
_eventController.sink.add(_toRegistrationEvent(extension,
kind: EventKind.kServiceUnregistered));
});
}
/// Returns the [VmServerConnection] for a given [extension], or `null` if
/// none is registered.
///
/// The result of this function should not be stored, because clients may
/// shut down at any time.
VmServerConnection clientFor(String extension) =>
_extensionToConnection[extension];
/// All of the currently registered extensions
Iterable<String> get registeredExtensions => _extensionToConnection.keys;
/// Emits an [Event] of type `ServiceRegistered` for all current and future
/// extensions that are registered, and `ServiceUnregistered` when those
/// clients disconnect.
Stream<Event> get onExtensionEvent => _eventController.stream
.transform(startWithMany(registeredExtensions.map(_toRegistrationEvent)));
/// Creates a `_Service` stream event, with a default kind of
/// [EventKind.kServiceRegistered].
Event _toRegistrationEvent(String method,
{String kind = EventKind.kServiceRegistered}) =>
Event()
..kind = kind
..service = method
..method = method;
}

View file

@ -1,99 +0,0 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
/// Copied from package:stream_transform.
/// Starts emitting values from [next] after the original stream is complete.
///
/// If the initial stream never finishes, the [next] stream will never be
/// listened to.
///
/// If a single-subscription follows the a broadcast stream it may be listened
/// to and never canceled.
///
/// If a broadcast stream follows any other stream it will miss any events which
/// occur before the first stream is done. If a broadcast stream follows a
/// single-subscription stream, pausing the stream while it is listening to the
/// second stream will cause events to be dropped rather than buffered.
StreamTransformer<T, T> followedBy<T>(Stream<T> next) => _FollowedBy<T>(next);
class _FollowedBy<T> extends StreamTransformerBase<T, T> {
final Stream<T> _next;
_FollowedBy(this._next);
@override
Stream<T> bind(Stream<T> first) {
var controller = first.isBroadcast
? StreamController<T>.broadcast(sync: true)
: StreamController<T>(sync: true);
var next = first.isBroadcast && !_next.isBroadcast
? _next.asBroadcastStream()
: _next;
StreamSubscription<T> subscription;
var currentStream = first;
var firstDone = false;
var secondDone = false;
Function currentDoneHandler;
listen() {
subscription = currentStream.listen(controller.add,
onError: controller.addError, onDone: () => currentDoneHandler());
}
onSecondDone() {
secondDone = true;
controller.close();
}
onFirstDone() {
firstDone = true;
currentStream = next;
currentDoneHandler = onSecondDone;
listen();
}
currentDoneHandler = onFirstDone;
controller.onListen = () {
assert(subscription == null);
listen();
if (!first.isBroadcast) {
controller
..onPause = () {
if (!firstDone || !next.isBroadcast) return subscription.pause();
subscription.cancel();
subscription = null;
}
..onResume = () {
if (!firstDone || !next.isBroadcast) return subscription.resume();
listen();
};
}
controller.onCancel = () {
if (secondDone) return null;
var toCancel = subscription;
subscription = null;
return toCancel.cancel();
};
};
return controller.stream;
}
}
StreamTransformer<T, T> startWithMany<T>(Iterable<T> initial) =>
startWithStream<T>(Stream.fromIterable(initial));
StreamTransformer<T, T> startWithStream<T>(Stream<T> initial) =>
StreamTransformer.fromBind((values) {
if (values.isBroadcast && !initial.isBroadcast) {
initial = initial.asBroadcastStream();
}
return initial.transform(followedBy(values));
});

View file

@ -1,22 +0,0 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:meta/meta.dart';
/// Map the URI to a WebSocket URI for the VM service protocol.
///
/// If the URI is already a VM Service WebSocket URI it will not be modified.
Uri convertToWebSocketUrl({@required Uri serviceProtocolUrl}) {
final isSecure = serviceProtocolUrl.isScheme('wss') ||
serviceProtocolUrl.isScheme('https');
final scheme = isSecure ? 'wss' : 'ws';
final path = serviceProtocolUrl.path.endsWith('/ws')
? serviceProtocolUrl.path
: (serviceProtocolUrl.path.endsWith('/')
? '${serviceProtocolUrl.path}ws'
: '${serviceProtocolUrl.path}/ws');
return serviceProtocolUrl.replace(scheme: scheme, path: path);
}

File diff suppressed because it is too large Load diff

View file

@ -1,26 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'vm_service.dart';
Future<VmService> vmServiceConnect(String host, int port, {Log log}) async {
WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
StreamController<String> controller = new StreamController();
socket.listen((data) => controller.add(data));
return new VmService(
controller.stream, (String message) => socket.add(message),
log: log, disposeHandler: () => socket.close());
}
Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
WebSocket socket = await WebSocket.connect(wsUri);
StreamController<String> controller = new StreamController();
socket.listen((data) => controller.add(data));
return new VmService(
controller.stream, (String message) => socket.add(message),
log: log, disposeHandler: () => socket.close());
}

View file

@ -1,21 +0,0 @@
name: vm_service
description: A library to access the VM Service API.
version: 1.0.0
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/sdk/pkg/vm_service/
environment:
sdk: '>=2.0.0 <3.0.0'
dependencies:
meta: ^1.0.2
dev_dependencies:
async: ^2.0.0
markdown: ^2.0.0
mockito: ^4.0.0
path: ^1.0.0
pedantic: ^1.7.0
pub_semver: ^1.0.0
test: ^1.0.0

View file

@ -1,443 +0,0 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@TestOn('vm')
import 'dart:async';
import 'dart:convert';
import 'package:async/async.dart';
import 'package:mockito/mockito.dart';
import 'package:pedantic/pedantic.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
void main() {
MockVmService serviceMock;
StreamController<Map<String, Object>> requestsController;
StreamController<Map<String, Object>> responsesController;
ServiceExtensionRegistry serviceRegistry;
setUp(() {
serviceMock = MockVmService();
requestsController = StreamController<Map<String, Object>>();
responsesController = StreamController<Map<String, Object>>();
serviceRegistry = ServiceExtensionRegistry();
VmServerConnection(requestsController.stream, responsesController.sink,
serviceRegistry, serviceMock);
});
tearDown(() {
requestsController.close();
responsesController.close();
});
group('method delegation', () {
test('works for simple methods', () {
var request = rpcRequest("getVersion");
var version = Version()
..major = 1
..minor = 0;
when(serviceMock.getVersion()).thenAnswer((_) => Future.value(version));
expect(responsesController.stream, emits(rpcResponse(version)));
requestsController.add(request);
});
test('works for methods with parameters', () {
var isolate = Isolate()
..id = '123'
..number = '0'
..startTime = 1
..runnable = true
..livePorts = 2
..pauseOnExit = false
..pauseEvent = (Event()
..kind = EventKind.kResume
..timestamp = 3)
..libraries = []
..breakpoints = [];
var request = rpcRequest("getIsolate", params: {'isolateId': isolate.id});
when(serviceMock.getIsolate(isolate.id))
.thenAnswer((Invocation invocation) {
expect(invocation.positionalArguments, equals([isolate.id]));
return Future.value(isolate);
});
expect(responsesController.stream, emits(rpcResponse(isolate)));
requestsController.add(request);
});
group('custom service extensions', () {
test('with no params or isolateId', () {
var extension = 'ext.cool';
var request = rpcRequest(extension, params: null);
var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(isNull, named: 'isolateId'),
args: argThat(isNull, named: 'args'),
)).thenAnswer((Invocation invocation) {
expect(invocation.namedArguments,
equals({Symbol('isolateId'): null, Symbol('args'): null}));
return Future.value(response);
});
expect(responsesController.stream, emits(rpcResponse(response)));
requestsController.add(request);
});
test('with isolateId and no other params', () {
var extension = 'ext.cool';
var request = rpcRequest(extension, params: {'isolateId': '1'});
var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(equals('1'), named: 'isolateId'),
args: argThat(equals({}), named: 'args'),
)).thenAnswer((Invocation invocation) {
expect(invocation.namedArguments,
equals({Symbol('isolateId'): '1', Symbol('args'): {}}));
return Future.value(response);
});
expect(responsesController.stream, emits(rpcResponse(response)));
requestsController.add(request);
});
test('with params and no isolateId', () {
var extension = 'ext.cool';
var params = {'cool': 'option'};
var request = rpcRequest(extension, params: params);
var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(isNull, named: 'isolateId'),
args: argThat(equals(params), named: 'args'),
)).thenAnswer((Invocation invocation) {
expect(invocation.namedArguments,
equals({Symbol('isolateId'): null, Symbol('args'): params}));
return Future.value(response);
});
expect(responsesController.stream, emits(rpcResponse(response)));
requestsController.add(request);
});
test('with params and isolateId', () {
var extension = 'ext.cool';
var params = {'cool': 'option'};
var request =
rpcRequest(extension, params: Map.of(params)..['isolateId'] = '1');
var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(equals("1"), named: 'isolateId'),
args: argThat(equals(params), named: 'args'),
)).thenAnswer((Invocation invocation) {
expect(invocation.namedArguments,
equals({Symbol('isolateId'): '1', Symbol('args'): params}));
return Future.value(response);
});
expect(responsesController.stream, emits(rpcResponse(response)));
requestsController.add(request);
});
});
});
group('error handling', () {
test('special cases RPCError instances', () {
var request = rpcRequest("getVersion");
var error =
RPCError('getVersion', 1234, 'custom message', {'custom': 'data'});
when(serviceMock.getVersion()).thenAnswer((_) => Future.error(error));
expect(responsesController.stream, emits(rpcErrorResponse(error)));
requestsController.add(request);
});
test('has a fallback for generic exceptions', () {
var request = rpcRequest("getVersion");
var error = UnimplementedError();
when(serviceMock.getVersion()).thenAnswer((_) => Future.error(error));
expect(
responsesController.stream.map((response) => '$response'),
emits(startsWith(
'{jsonrpc: 2.0, error: {code: -32603, message: UnimplementedError')));
requestsController.add(request);
});
});
group('streams', () {
test('can be listened to and canceled', () async {
var streamId = 'Isolate';
var responseQueue = StreamQueue(responsesController.stream);
StreamController<Event> eventController;
{
var request =
rpcRequest('streamListen', params: {'streamId': streamId});
var response = Success();
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
await expect(responseQueue, emitsThrough(rpcResponse(response)));
eventController = serviceMock.streamControllers[streamId];
var events = [
Event()
..kind = EventKind.kIsolateStart
..timestamp = 0,
Event()
..kind = EventKind.kIsolateExit
..timestamp = 1,
];
events.forEach(eventController.add);
await expect(
responseQueue,
emitsInOrder(
events.map((event) => streamNotifyResponse(streamId, event))));
}
{
var request =
rpcRequest('streamCancel', params: {'streamId': streamId});
var response = Success();
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
await expect(responseQueue, emitsThrough(rpcResponse(response)));
var nextEvent = Event()
..kind = EventKind.kIsolateReload
..timestamp = 2;
eventController.add(nextEvent);
expect(responseQueue,
neverEmits(streamNotifyResponse(streamId, nextEvent)));
await pumpEventQueue();
await eventController.close();
await responsesController.close();
}
});
test("can't be listened to twice", () {
var streamId = 'Isolate';
var responseQueue = StreamQueue(responsesController.stream);
{
var request =
rpcRequest('streamListen', params: {'streamId': streamId});
var response = Success();
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
expect(responseQueue, emitsThrough(rpcResponse(response)));
}
{
var request =
rpcRequest('streamListen', params: {'streamId': streamId});
var response = Success();
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
expect(
responseQueue,
emitsThrough(rpcErrorResponse(
RPCError('streamSubcribe', 103, 'Stream already subscribed', {
'details': "The stream '$streamId' is already subscribed",
}))));
}
});
test("can't cancel a stream that isn't being listened to", () {
var streamId = 'Isolate';
var responseQueue = StreamQueue(responsesController.stream);
var request = rpcRequest('streamCancel', params: {'streamId': streamId});
var response = Success();
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
expect(
responseQueue,
emitsThrough(rpcErrorResponse(
RPCError('streamCancel', 104, 'Stream not subscribed', {
'details': "The stream '$streamId' is not subscribed",
}))));
});
group('Service', () {
final serviceStream = 'Service';
test('gives register and unregister events', () async {
var serviceId = 'ext.test.service';
var serviceRegisteredEvent = streamNotifyResponse(
serviceStream,
Event()
..kind = EventKind.kServiceRegistered
..method = serviceId
..service = serviceId);
var serviceUnRegisteredEvent = streamNotifyResponse(
serviceStream,
Event()
..kind = EventKind.kServiceUnregistered
..method = serviceId
..service = serviceId);
requestsController.add(
rpcRequest('streamListen', params: {'streamId': serviceStream}));
requestsController
.add(rpcRequest('registerService', params: {'service': serviceId}));
await expect(
responsesController.stream, emitsThrough(serviceRegisteredEvent));
// Connect another client to get the previous register events and the
// unregister event.
var requestsController2 = StreamController<Map<String, Object>>();
var responsesController2 = StreamController<Map<String, Object>>();
addTearDown(() {
requestsController2.close();
responsesController2.close();
});
VmServerConnection(requestsController2.stream,
responsesController2.sink, serviceRegistry, null);
expect(
responsesController2.stream,
emitsThrough(emitsInOrder(
[serviceRegisteredEvent, serviceUnRegisteredEvent])));
// Should get the previously registered extension event, as well as
// the unregister event when the client disconnects.
requestsController2.add(
rpcRequest('streamListen', params: {'streamId': serviceStream}));
// Need to give the client a chance to subscribe.
await pumpEventQueue();
unawaited(requestsController.close());
// Give the old client a chance to shut down
await pumpEventQueue();
// Connect yet another client, it should get zero registration or
// unregistration events.
var requestsController3 = StreamController<Map<String, Object>>();
var responsesController3 = StreamController<Map<String, Object>>();
VmServerConnection(requestsController3.stream,
responsesController3.sink, serviceRegistry, null);
expect(
responsesController3.stream,
neverEmits(
anyOf(serviceRegisteredEvent, serviceUnRegisteredEvent)));
// Give it a chance to deliver events.
await pumpEventQueue();
// Disconnect the client so the test can shut down.
unawaited(requestsController3.close());
unawaited(responsesController3.close());
});
});
});
group('registerService', () {
test('can delegate requests between clients', () async {
var serviceId = 'ext.test.service';
var responseQueue = StreamQueue(responsesController.stream);
var clientInputController =
StreamController<Map<String, Object>>.broadcast();
var clientOutputController =
StreamController<Map<String, Object>>.broadcast();
var client = VmService(clientInputController.stream.map(jsonEncode),
(String message) => clientOutputController.add(jsonDecode(message)),
disposeHandler: () async {
await clientInputController.close();
await clientOutputController.close();
});
var clientConnection = VmServerConnection(clientOutputController.stream,
clientInputController.sink, serviceRegistry, serviceMock);
var requestParams = {'foo': 'bar'};
var expectedResponse = Response()..json = {'zap': 'zip'};
await client.registerService(serviceId, null);
// Duplicate registrations should fail.
expect(client.registerService(serviceId, null),
throwsA(const TypeMatcher<RPCError>()));
await client.registerServiceCallback(serviceId, (request) async {
expect(request, equals(requestParams));
return {'result': expectedResponse.toJson()};
});
var serviceRequest = rpcRequest(serviceId, params: requestParams);
requestsController.add(serviceRequest);
expect(await responseQueue.next, rpcResponse(expectedResponse));
// Kill the client that registered the handler, it should now fall back
// on `callServiceExtension`.
client.dispose();
// This should complete as well.
await clientConnection.done;
var mockResponse = Response()..json = {'mock': 'response'};
when(serviceMock.callServiceExtension(serviceId,
args: argThat(equals(requestParams), named: 'args'),
isolateId: argThat(isNull, named: 'isolateId')))
.thenAnswer((_) async => mockResponse);
requestsController.add(serviceRequest);
expect(await responseQueue.next, rpcResponse(mockResponse));
});
});
}
Map<String, Object> rpcRequest(String method,
{Map<String, Object> params = const {}, String id = "1"}) =>
{
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": id,
};
Map<String, Object> rpcResponse(Response response, {String id = "1"}) => {
'jsonrpc': '2.0',
'id': id,
'result': response.toJson(),
};
Map<String, Object> rpcErrorResponse(Object error, {String id = "1"}) {
Map<String, Object> errorJson;
if (error is RPCError) {
errorJson = {
'code': error.code,
'message': error.message,
};
if (error.data != null) {
errorJson['data'] = error.data;
}
} else {
errorJson = {
'code': -32603,
'message': error.toString(),
};
}
return {
'jsonrpc': '2.0',
'error': errorJson,
'id': id,
};
}
Map<String, Object> streamNotifyResponse(String streamId, Event event) {
return {
'jsonrpc': '2.0',
'method': 'streamNotify',
'params': {
'streamId': '$streamId',
'event': event.toJson(),
},
};
}
class MockVmService extends Mock implements VmServiceInterface {
final streamControllers = <String, StreamController<Event>>{};
@override
Stream<Event> onEvent(String streamId) => streamControllers
.putIfAbsent(streamId, () => StreamController<Event>())
.stream;
}

View file

@ -1,35 +0,0 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:test/test.dart';
import 'package:vm_service/utils.dart';
void main() {
test('convertToWebSocketUrl maps URIs correctly', () {
final testCases = {
'http://localhost:123/': 'ws://localhost:123/ws',
'https://localhost:123/': 'wss://localhost:123/ws',
'ws://localhost:123/': 'ws://localhost:123/ws',
'wss://localhost:123/': 'wss://localhost:123/ws',
'http://localhost:123/ABCDEF=/': 'ws://localhost:123/ABCDEF=/ws',
'https://localhost:123/ABCDEF=/': 'wss://localhost:123/ABCDEF=/ws',
'ws://localhost:123/ABCDEF=/': 'ws://localhost:123/ABCDEF=/ws',
'wss://localhost:123/ABCDEF=/': 'wss://localhost:123/ABCDEF=/ws',
'http://localhost:123': 'ws://localhost:123/ws',
'https://localhost:123': 'wss://localhost:123/ws',
'ws://localhost:123': 'ws://localhost:123/ws',
'wss://localhost:123': 'wss://localhost:123/ws',
'http://localhost:123/ABCDEF=': 'ws://localhost:123/ABCDEF=/ws',
'https://localhost:123/ABCDEF=': 'wss://localhost:123/ABCDEF=/ws',
'ws://localhost:123/ABCDEF=': 'ws://localhost:123/ABCDEF=/ws',
'wss://localhost:123/ABCDEF=': 'wss://localhost:123/ABCDEF=/ws',
};
testCases.forEach((String input, String expected) {
final inputUri = Uri.parse(input);
final actualUri = convertToWebSocketUrl(serviceProtocolUrl: inputUri);
expect(actualUri.toString(), equals(expected));
});
});
}

View file

@ -1,30 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library generate_vm_service_common;
import 'package:markdown/markdown.dart';
import 'package:pub_semver/pub_semver.dart';
import 'src_gen_common.dart';
/// [ApiParseUtil] contains top level parsing utilities.
class ApiParseUtil {
/// Extract the current VM Service version number as a String.
static String parseVersionString(List<Node> nodes) =>
parseVersionSemVer(nodes).toString();
static Version parseVersionSemVer(List<Node> nodes) {
final RegExp regex = new RegExp(r'[\d.]+');
// Extract version from header: `# Dart VM Service Protocol 2.0`.
Element node = nodes.firstWhere((n) => isH1(n));
Text text = node.children[0];
Match match = regex.firstMatch(text.text);
if (match == null) throw 'Unable to locate service protocol version';
// Append a `.0`.
return new Version.parse('${match.group(0)}.0');
}
}

View file

@ -1,172 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library parser;
class Token {
static final RegExp _alpha = new RegExp(r'^[0-9a-zA-Z_\-@]+$');
final String text;
Token next;
Token(this.text);
bool get eof => text == null;
bool get isName {
if (text == null || text.isEmpty) return false;
return _alpha.hasMatch(text);
}
bool get isComment => text != null && text.startsWith('//');
String toString() => text == null ? 'EOF' : text;
}
class Tokenizer {
static final alphaNum =
'@abcdefghijklmnopqrstuvwxyz-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
static final whitespace = ' \n\t\r';
String text;
Token _head;
Token _last;
Tokenizer(this.text);
Token tokenize() {
_emit(null);
for (int i = 0; i < text.length; i++) {
String c = text[i];
if (whitespace.contains(c)) {
// skip
} else if (c == '/' && _peek(i) == '/') {
int index = text.indexOf('\n', i);
if (index == -1) index = text.length;
_emit(text.substring(i, index));
i = index;
} else if (alphaNum.contains(c)) {
int start = i;
while (alphaNum.contains(_peek(i))) {
i++;
}
_emit(text.substring(start, i + 1));
} else {
_emit(c);
}
}
_emit(null);
_head = _head.next;
return _head;
}
void _emit(String value) {
Token token = new Token(value);
if (_head == null) _head = token;
if (_last != null) _last.next = token;
_last = token;
}
String _peek(int i) {
i += 1;
return i < text.length ? text[i] : new String.fromCharCodes([0]);
}
String toString() {
StringBuffer buf = new StringBuffer();
Token t = _head;
buf.write('[${t}]\n');
while (!t.eof) {
t = t.next;
buf.write('[${t}]\n');
}
return buf.toString().trim();
}
}
abstract class Parser {
final Token startToken;
Token current;
Parser(this.startToken);
Token expect(String text) {
Token t = advance();
if (text != t.text) fail('expected ${text}, got ${t}');
return t;
}
bool consume(String text) {
if (peek().text == text) {
advance();
return true;
} else {
return false;
}
}
Token peek() =>
current == null ? startToken : current.eof ? current : current.next;
Token expectName() {
Token t = advance();
if (!t.isName) fail('expected name token, got ${t}');
return t;
}
Token advance() {
if (current == null) {
current = startToken;
} else if (!current.eof) {
current = current.next;
}
return current;
}
String collectComments() {
StringBuffer buf = new StringBuffer();
while (peek().isComment) {
Token t = advance();
String str = t.text.substring(2);
if (str.startsWith(' ')) str = str.substring(1);
if (str.startsWith(' ')) {
buf.write('\n - ${str.substring(2)}');
} else if (str.isEmpty) {
buf.write('\n\n');
} else {
buf.write('${str} ');
}
}
if (buf.isEmpty) return null;
return buf
.toString()
.split('\n')
.map((line) => line.trimRight())
.join('\n')
.trim();
}
void validate(bool result, String message) {
if (!result) throw 'expected ${message}';
}
void fail(String message) => throw message;
}

View file

@ -1,93 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library src_gen_common;
import 'package:markdown/markdown.dart';
const int RUNE_SPACE = 32;
const int RUNE_EOL = 10;
const int RUNE_LEFT_CURLY = 123;
const int RUNE_RIGHT_CURLY = 125;
final RegExp _wsRegexp = new RegExp(r'\s+');
String collapseWhitespace(String str) => str.replaceAll(_wsRegexp, ' ');
bool isEmphasis(Node node) => node is Element && node.tag == 'em';
bool isPara(Node node) => node is Element && node.tag == 'p';
bool isBlockquote(Node node) => node is Element && node.tag == 'blockquote';
bool isPre(Node node) => node is Element && node.tag == 'pre';
bool isH1(Node node) => node is Element && node.tag == 'h1';
bool isH3(Node node) => node is Element && node.tag == 'h3';
bool isHeader(Node node) => node is Element && node.tag.startsWith('h');
String textForElement(Node node) =>
(((node as Element).children.first) as Text).text;
String textForCode(Node node) =>
textForElement((node as Element).children.first);
/// foo ==> Foo
String titleCase(String str) =>
str.substring(0, 1).toUpperCase() + str.substring(1);
/// FooBar ==> fooBar
String lowerTitleCase(String str) =>
str.substring(0, 1).toLowerCase() + str.substring(1);
String joinLast(Iterable<String> strs, String join, [String last]) {
if (strs.isEmpty) return '';
List list = strs.toList();
if (list.length == 1) return list.first;
StringBuffer buf = new StringBuffer();
for (int i = 0; i < list.length; i++) {
if (i > 0) {
if (i + 1 == list.length && last != null) {
buf.write(last);
} else {
buf.write(join);
}
}
buf.write(list[i]);
}
return buf.toString();
}
/// Wrap a string on column boundaries.
String wrap(String str, [int col = 80]) {
// The given string could contain newlines.
List<String> lines = str.split('\n');
return lines.map((l) => _simpleWrap(l, col)).join('\n');
}
/// Wrap a string ignoring newlines.
String _simpleWrap(String str, [int col = 80]) {
List<String> lines = [];
while (str.length > col) {
int index = col;
while (index > 0 && str.codeUnitAt(index) != RUNE_SPACE) {
index--;
}
if (index == 0) {
index = str.indexOf(' ');
if (index == -1) {
lines.add(str);
str = '';
} else {
lines.add(str.substring(0, index).trim());
str = str.substring(index).trim();
}
} else {
lines.add(str.substring(0, index).trim());
str = str.substring(index).trim();
}
}
if (str.isNotEmpty) lines.add(str);
return lines.join('\n');
}

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// A library to generate Dart source code.
library src_gen_dart;
import '../common/src_gen_common.dart';
/// A class used to generate Dart source code. This class facilitates writing out
/// dartdoc comments, automatically manages indent by counting curly braces, and
/// automatically wraps doc comments on 80 char column boundaries.
class DartGenerator {
static const DEFAULT_COLUMN_BOUNDARY = 80;
final int colBoundary;
String _indent = "";
final StringBuffer _buf = new StringBuffer();
bool _previousWasEol = false;
DartGenerator({this.colBoundary = DEFAULT_COLUMN_BOUNDARY});
/// Write out the given dartdoc text, wrapping lines as necessary to flow
/// along the column boundary. If [preferSingle] is true, and the docs would
/// fit on a single line, use `///` dartdoc style.
void writeDocs(String docs) {
if (docs == null) return;
docs = wrap(docs.trim(), colBoundary - _indent.length - 4);
// docs = docs.replaceAll('*/', '/');
// docs = docs.replaceAll('/*', r'/\*');
docs.split('\n').forEach((line) => _writeln('/// ${line}'.trimRight()));
// if (!docs.contains('\n') && preferSingle) {
// _writeln("/// ${docs}", true);
// } else {
// _writeln("/**", true);
// _writeln(" * ${docs.replaceAll("\n", "\n * ")}", true);
// _writeln(" */", true);
// }
}
/// Write out the given Dart statement and terminate it with an eol. If the
/// statement will overflow the column boundary, attempt to wrap it at
/// reasonable places.
void writeStatement(String str) {
if (_indent.length + str.length > colBoundary) {
// Split the line on the first '('. Currently, we don't do anything
// fancier then that. This takes the edge off the long lines.
int index = str.indexOf('(');
if (index == -1) {
writeln(str);
} else {
writeln(str.substring(0, index + 1));
writeln(" ${str.substring(index + 1)}");
}
} else {
writeln(str);
}
}
void writeln([String str = ""]) => _write("${str}\n");
void write(String str) => _write(str);
void out(String str) => _buf.write(str);
void _writeln([String str = "", bool ignoreCurlies = false]) =>
_write("${str}\n", ignoreCurlies);
void _write(String str, [bool ignoreCurlies = false]) {
for (final int rune in str.runes) {
if (!ignoreCurlies) {
if (rune == RUNE_LEFT_CURLY) {
_indent = "${_indent} ";
} else if (rune == RUNE_RIGHT_CURLY && _indent.length >= 2) {
_indent = _indent.substring(2);
}
}
if (_previousWasEol && rune != RUNE_EOL) {
_buf.write(_indent);
}
_buf.write(new String.fromCharCode(rune));
_previousWasEol = rune == RUNE_EOL;
}
}
String toString() => _buf.toString();
}

View file

@ -1,155 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'package:markdown/markdown.dart';
import 'package:path/path.dart';
import 'package:pub_semver/pub_semver.dart';
import 'common/generate_common.dart';
import 'dart/generate_dart.dart' as dart show Api, api, DartGenerator;
import 'java/generate_java.dart' as java show Api, api, JavaGenerator;
final bool _stampPubspecVersion = false;
/// Parse the 'service.md' into a model and generate both Dart and Java
/// libraries.
main(List<String> args) async {
bool generateJava = false;
if (args.length != 0) {
if ((args.length == 1) && (args.first == '--generate-java')) {
generateJava = true;
} else {
print('Invalid options: $args. Usage: dart generate [--generate-java].');
return;
}
}
String appDirPath = dirname(Platform.script.toFilePath());
// Parse service.md into a model.
var file =
new File(join(appDirPath, '../../../runtime/vm/service/service.md'));
var document = new Document();
StringBuffer buf = new StringBuffer(file.readAsStringSync());
buf.writeln();
buf.write(
new File(join(appDirPath, 'service_undocumented.md')).readAsStringSync());
var nodes = document.parseLines(buf.toString().split('\n'));
print('Parsed ${file.path}.');
print('Service protocol version ${ApiParseUtil.parseVersionString(nodes)}.');
// Generate code from the model.
await _generateDart(appDirPath, nodes);
if (generateJava) {
await _generateJava(appDirPath, nodes);
}
await _generateAsserts(appDirPath, nodes);
}
_generateDart(String appDirPath, List<Node> nodes) async {
print('');
var outDirPath = normalize(join(appDirPath, '..', 'lib'));
var outDir = new Directory(outDirPath);
if (!outDir.existsSync()) outDir.createSync(recursive: true);
var outputFile = new File(join(outDirPath, 'vm_service.dart'));
var generator = new dart.DartGenerator();
dart.api = new dart.Api();
dart.api.parse(nodes);
dart.api.generate(generator);
outputFile.writeAsStringSync(generator.toString());
Process.runSync('dartfmt', ['-w', outDirPath]);
if (_stampPubspecVersion) {
// Update the pubspec file.
Version version = ApiParseUtil.parseVersionSemVer(nodes);
_stampPubspec(version);
// Validate that the changelog contains an entry for the current version.
_checkUpdateChangelog(version);
}
print('Wrote Dart to ${outputFile.path}.');
}
_generateJava(String appDirPath, List<Node> nodes) async {
print('');
var srcDirPath = normalize(join(appDirPath, '..', 'java', 'src', 'gen'));
assert(new Directory(srcDirPath).existsSync());
var generator = new java.JavaGenerator(srcDirPath);
java.api = new java.Api();
java.api.parse(nodes);
java.api.generate(generator);
// Generate a version file.
Version version = ApiParseUtil.parseVersionSemVer(nodes);
File file = new File(join('java', 'version.properties'));
file.writeAsStringSync('version=${version.major}.${version.minor}\n');
print('Wrote Java to $srcDirPath.');
}
_generateAsserts(String appDirPath, List<Node> nodes) async {
print('');
var outDirPath = normalize(join(appDirPath, '..', 'example'));
var outDir = new Directory(outDirPath);
if (!outDir.existsSync()) outDir.createSync(recursive: true);
var outputFile = new File(join(outDirPath, 'vm_service_assert.dart'));
var generator = new dart.DartGenerator();
dart.api = new dart.Api();
dart.api.parse(nodes);
dart.api.generateAsserts(generator);
outputFile.writeAsStringSync(generator.toString());
Process.runSync('dartfmt', ['-w', outDirPath]);
if (_stampPubspecVersion) {
// Update the pubspec file.
Version version = ApiParseUtil.parseVersionSemVer(nodes);
_stampPubspec(version);
// Validate that the changelog contains an entry for the current version.
_checkUpdateChangelog(version);
}
print('Wrote Dart to ${outputFile.path}.');
}
// Push the major and minor versions into the pubspec.
void _stampPubspec(Version version) {
final String pattern = 'version: ';
File file = new File('pubspec.yaml');
String text = file.readAsStringSync();
bool found = false;
text = text.split('\n').map((line) {
if (line.startsWith(pattern)) {
found = true;
Version v = new Version.parse(line.substring(pattern.length));
String pre = v.preRelease.isEmpty ? null : v.preRelease.join('-');
String build = v.build.isEmpty ? null : v.build.join('+');
v = new Version(version.major, version.minor, v.patch,
pre: pre, build: build);
return '${pattern}${v.toString()}';
} else {
return line;
}
}).join('\n');
if (!found) throw '`${pattern}` not found';
file.writeAsStringSync(text);
}
void _checkUpdateChangelog(Version version) {
// Look for `## major.minor`.
String check = '## ${version.major}.${version.minor}';
File file = new File('CHANGELOG.md');
String text = file.readAsStringSync();
bool containsReleaseNotes =
text.split('\n').any((line) => line.startsWith(check));
if (!containsReleaseNotes) {
throw '`${check}` not found in the CHANGELOG.md file';
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,307 +0,0 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// A library to generate Java source code. See [JavaGenerator].
library src_gen_java;
import 'dart:io';
import 'package:path/path.dart';
import '../common/src_gen_common.dart';
/// The maximum length for javadoc comments.
int colBoundary = 100;
/// The header for every generated file.
String fileHeader;
String classNameFor(String typeName) {
// Convert ElementList<Foo> param declarations to List<Foo> declarations.
if (typeName.startsWith('ElementList<')) {
return typeName.substring('Element'.length);
}
var index = typeName.lastIndexOf('.');
typeName = index > 0 ? typeName.substring(index + 1) : typeName;
if (typeName.startsWith('_')) typeName = typeName.substring(1);
return typeName;
}
String pkgNameFor(String typeName) {
var index = typeName.lastIndexOf('.');
return index > 0 ? typeName.substring(0, index) : '';
}
typedef WriteStatements = void Function(StatementWriter writer);
typedef WriteType = void Function(TypeWriter writer);
/// [JavaGenerator] generates java source files, one per Java type.
/// Typical usage:
///
/// var generator = new JavaGenerator('/path/to/java/src');
/// generator.writeType('some.package.Foo', (TypeWriter) writer) {
/// ...
/// });
/// ...
///
class JavaGenerator {
/// The java source directory into which files are generated.
final String srcDirPath;
JavaGenerator(this.srcDirPath);
/// Generate a Java class/interface in the given package
void writeType(String typeName, WriteType write) {
var classWriter = new TypeWriter(typeName);
write(classWriter);
var pkgDirPath = join(srcDirPath, joinAll(pkgNameFor(typeName).split('.')));
var pkgDir = new Directory(pkgDirPath);
if (!pkgDir.existsSync()) pkgDir.createSync(recursive: true);
var classFilePath = join(pkgDirPath, '${classNameFor(typeName)}.java');
var classFile = new File(classFilePath);
classFile.writeAsStringSync(classWriter.toSource());
}
}
class JavaMethodArg {
final String name;
final String typeName;
JavaMethodArg(this.name, this.typeName);
}
class StatementWriter {
final TypeWriter typeWriter;
final StringBuffer _content = new StringBuffer();
StatementWriter(this.typeWriter);
void addImport(String typeName) {
typeWriter.addImport(typeName);
}
void addLine(String line) {
_content.writeln(' $line');
}
String toSource() => _content.toString();
}
/// [TypeWriter] describes a Java type to be generated.
/// Typical usage:
///
/// writer.addImport('package.one.Bar');
/// writer.addImport('package.two.*');
/// writer.superclassName = 'package.three.Blat';
/// writer.addMethod('foo', [
/// new JavaMethodArg('arg1', 'LocalType'),
/// new JavaMethodArg('arg2', 'java.util.List'),
/// ], (StatementWriter writer) {
/// ...
/// });
///
/// The [toSource()] method generates the source,
/// but need not be called if used in conjunction with
/// [JavaGenerator].
class TypeWriter {
final String pkgName;
final String className;
bool isInterface = false;
bool isEnum = false;
String javadoc;
String modifiers = 'public';
final Set<String> _imports = new Set<String>();
String superclassName;
List<String> interfaceNames = <String>[];
final StringBuffer _content = new StringBuffer();
final List<String> _fields = <String>[];
final Map<String, String> _methods = new Map<String, String>();
TypeWriter(String typeName)
: this.pkgName = pkgNameFor(typeName),
this.className = classNameFor(typeName);
String get kind {
if (isInterface) return 'interface';
if (isEnum) return 'enum';
return 'class';
}
void addConstructor(Iterable<JavaMethodArg> args, WriteStatements write,
{String javadoc, String modifiers = 'public'}) {
_content.writeln();
if (javadoc != null && javadoc.isNotEmpty) {
_content.writeln(' /**');
wrap(javadoc.trim(), colBoundary - 6)
.split('\n')
.forEach((line) => _content.writeln(' * $line'));
_content.writeln(' */');
}
_content.write(' $modifiers $className(');
_content.write(
args.map((a) => '${classNameFor(a.typeName)} ${a.name}').join(', '));
_content.write(')');
if (write != null) {
_content.writeln(' {');
StatementWriter writer = new StatementWriter(this);
write(writer);
_content.write(writer.toSource());
_content.writeln(' }');
} else {
_content.writeln(';');
}
}
void addEnumValue(
String name, {
String javadoc,
bool isLast = false,
}) {
_content.writeln();
if (javadoc != null && javadoc.isNotEmpty) {
_content.writeln(' /**');
wrap(javadoc.trim(), colBoundary - 6)
.split('\n')
.forEach((line) => _content.writeln(' * $line'));
_content.writeln(' */');
}
_content.write(' $name');
if (!isLast) {
_content.writeln(',');
} else {
_content.writeln();
}
}
void addField(String name, String typeName,
{String modifiers = 'public', String value, String javadoc}) {
var fieldDecl = new StringBuffer();
if (javadoc != null && javadoc.isNotEmpty) {
fieldDecl.writeln(' /**');
wrap(javadoc.trim(), colBoundary - 6)
.split('\n')
.forEach((line) => fieldDecl.writeln(' * $line'));
fieldDecl.writeln(' */');
}
fieldDecl.write(' ');
if (modifiers != null && modifiers.isNotEmpty) {
fieldDecl.write('$modifiers ');
}
fieldDecl.write('$typeName $name');
if (value != null && value.isNotEmpty) {
fieldDecl.write(' = $value');
}
fieldDecl.writeln(';');
_fields.add(fieldDecl.toString());
}
void addImport(String typeName) {
if (typeName == null || typeName.isEmpty) return;
var pkgName = pkgNameFor(typeName);
if (pkgName.isNotEmpty && pkgName != this.pkgName) {
_imports.add(typeName);
}
}
void addMethod(
String name,
Iterable<JavaMethodArg> args,
WriteStatements write, {
String javadoc,
String modifiers = 'public',
String returnType = 'void',
bool isOverride = false,
}) {
var methodDecl = new StringBuffer();
if (javadoc != null && javadoc.isNotEmpty) {
methodDecl.writeln(' /**');
wrap(javadoc.trim(), colBoundary - 6)
.split('\n')
.forEach((line) => methodDecl.writeln(' * $line'.trimRight()));
methodDecl.writeln(' */');
}
if (isOverride) {
methodDecl.writeln(' @Override');
}
methodDecl.write(' ');
if (modifiers != null && modifiers.isNotEmpty) {
if (!isInterface || modifiers != 'public') {
methodDecl.write('$modifiers ');
}
}
methodDecl.write('$returnType $name(');
methodDecl.write(args
.map((JavaMethodArg arg) => '${classNameFor(arg.typeName)} ${arg.name}')
.join(', '));
methodDecl.write(')');
if (write != null) {
methodDecl.writeln(' {');
StatementWriter writer = new StatementWriter(this);
write(writer);
methodDecl.write(writer.toSource());
methodDecl.writeln(' }');
} else {
methodDecl.writeln(';');
}
String key = (modifiers != null && modifiers.contains('public'))
? '1 $name('
: '2 $name(';
key = args.fold(key, (String k, JavaMethodArg a) => '$k${a.typeName},');
_methods[key] = methodDecl.toString();
}
String toSource() {
var buffer = new StringBuffer();
if (fileHeader != null) buffer.write(fileHeader);
if (pkgName != null) {
buffer.writeln('package $pkgName;');
buffer.writeln();
}
buffer.writeln('// This is a generated file.');
buffer.writeln();
addImport(superclassName);
interfaceNames.forEach((t) => addImport(t));
if (_imports.isNotEmpty) {
var sorted = _imports.toList()..sort();
for (String typeName in sorted) {
buffer.writeln('import $typeName;');
}
buffer.writeln();
}
if (javadoc != null && javadoc.isNotEmpty) {
buffer.writeln('/**');
wrap(javadoc.trim(), colBoundary - 4)
.split('\n')
.forEach((line) => buffer.writeln(' * $line'));
buffer.writeln(' */');
}
buffer.writeln('@SuppressWarnings({"WeakerAccess", "unused"})');
buffer.write('$modifiers $kind $className');
if (superclassName != null) {
buffer.write(' extends ${classNameFor(superclassName)}');
}
if (interfaceNames.isNotEmpty) {
var classNames = interfaceNames.map((t) => classNameFor(t));
buffer.write(
' ${isInterface ? 'extends' : 'implements'} ${classNames.join(', ')}');
}
buffer.writeln(' {');
buffer.write(_content.toString());
_fields.forEach((f) {
buffer.writeln();
buffer.write(f);
});
_methods.keys.toList()
..sort()
..forEach((String methodName) {
buffer.writeln();
buffer.write(_methods[methodName]);
});
buffer.writeln('}');
return buffer.toString();
}
}

View file

@ -1,136 +0,0 @@
<!-- TODO(bkonyi): Eventually remove this file once all methods and classes are
either officially supported or have their uses removed throughout tooling.-->
** This file is locked as of 2019/07/19 and no further additions will be
accepted. If you require access to a private API in the service protocol,
please reach out to bkonyi@.**
Undocumented (and currently unsupported) service methods and classes.
### _collectAllGarbage
```
Success _collectAllGarbage(string isolateId)
```
Trigger a full GC, collecting all unreachable or weakly reachable objects.
### _requestHeapSnapshot
```
Success _requestHeapSnapshot(string isolateId, string roots, bool collectGarbage)
```
_roots_ is one of User or VM. The results are returned as a stream of
[_Graph] events.
### _clearCpuProfile
```
Success _clearCpuProfile(string isolateId)
```
### _getCpuProfile
```
_CpuProfile _getCpuProfile(string isolateId, string tags)
```
_tags_ is one of UserVM, UserOnly, VMUser, VMOnly, or None.
### _CpuProfile
```
class _CpuProfile extends Response {
int sampleCount;
int samplePeriod;
int stackDepth;
double timeSpan;
int timeOriginMicros;
int timeExtentMicros;
CodeRegion[] codes;
ProfileFunction[] functions;
int[] exclusiveCodeTrie;
int[] inclusiveCodeTrie;
int[] exclusiveFunctionTrie;
int[] inclusiveFunctionTrie;
}
```
### CodeRegion
```
class CodeRegion {
string kind;
int inclusiveTicks;
int exclusiveTicks;
@Code code;
}
```
<!-- <string|int>[] ticks -->
### ProfileFunction
```
class ProfileFunction {
string kind;
int inclusiveTicks;
int exclusiveTicks;
@Function function;
int[] codes;
}
```
<!-- <string|int>[] ticks -->
### AllocationProfile
```
class AllocationProfile extends Response {
string dateLastServiceGC;
ClassHeapStats[] members;
}
```
<!-- TODO: int dateLastServiceGC -->
### ClassHeapStats
```
class ClassHeapStats extends Response {
@Class class;
int[] new;
int[] old;
int promotedBytes;
int promotedInstances;
}
```
### HeapSpace
```
class HeapSpace extends Response {
double avgCollectionPeriodMillis;
int capacity;
int collections;
int external;
String name;
double time;
int used;
}
```
<!-- _CpuProfile -->
<!--
counters: _JsonMap
codes: JSArray
functions: JSArray
exclusiveCodeTrie: JSArray
inclusiveCodeTrie: JSArray
exclusiveFunctionTrie: JSArray
inclusiveFunctionTrie: JSArray
-->
<!-- _getCpuProfileTimeline -->
<!-- _getAllocationSamples -->