dart-sdk/sdk/lib/vmservice/client.dart
Vyacheslav Egorov b2eab8b96e [VM/Service] Restore zero-copying handling of JSON messages in vmservice.
In 5a44162c97 in attempt to adhere to declared
method signatures we lost zero-copying JSON decoding of responses from
VM: `Message.sendToVM` was changed to always decode the response into
string before passing it to the caller and the logic to use fused
JSON decoding was removed. This increased peak memory consumption by
the VM Service.

This commit addresses the issue by restoring the zero-copying JSON decoding
logic while adding a wrapper around responses that make it clear what kind
of data is passed around and how that data is encoded and handled.

We introduce a class `Response` which can contain either a Dart string, a
binary data (represented as a Uint8List) or utf8 encoded string (represented
as a Uint8List). This class is used in all places where previously a String
or dynamic were used, e.g. MessageRouter.routeRequest is changed to return
Future<Response> rather than Future<String>. This allows callees to
decode JSON responses without copying them into Dart heap while
maintaining sufficient level of typing to make the code easy to reason about.

This commit also removes some dead code from the VM service related to old
Service API and TAR assets unpacking (which has been long done in C++).

Bug: https://github.com/flutter/flutter/issues/13626
Change-Id: Ifbba56944a552034a0f802a965a313326a1236e7
Reviewed-on: https://dart-review.googlesource.com/30280
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2017-12-18 19:06:06 +00:00

66 lines
2 KiB
Dart

// Copyright (c) 2013, 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.
part of dart._vmservice;
typedef void ClientServiceHandle(Message response);
// A service client.
abstract class Client {
final VMService service;
final bool sendEvents;
/// A set streamIds which describes the streams the client is connected to
final Set<String> streams = new Set<String>();
/// Services registered and their aliases
/// key: service
/// value: alias
final Map<String, String> services = new Map<String, String>();
/// Callbacks registered for service invocations set to the client
/// key: RPC id used for the request
/// value: callback that should be invoked
final Map<String, ClientServiceHandle> serviceHandles =
new Map<String, ClientServiceHandle>();
Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
service._addClient(this);
}
// Disconnects the client.
disconnect();
/// When implementing, call [close] when the network connection closes.
void close() {
service._removeClient(this);
}
/// Call to process a request. Response will be posted with 'seq'.
void onRequest(Message message) {
// In JSON-RPC 2.0 messages with and id are Request and must be answered
// http://www.jsonrpc.org/specification#notification
service.routeRequest(message).then(post);
}
void onResponse(Message message) {
service.routeResponse(message);
}
/// Call to process a notification. Response will not be posted.
void onNotification(Message message) {
// In JSON-RPC 2.0 messages without an id are Notification
// and should not be answered
// http://www.jsonrpc.org/specification#notification
service.routeRequest(message);
}
// Sends a result to the client. Implemented in subclasses.
void post(Response result);
dynamic toJson() {
return {};
}
}