blob: 8dc158d45068b891c0297de12e563e2337b3964a [file] [log] [blame]
// Copyright 2015 Google. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
library crmux.forwarder;
import 'dart:async';
import 'dart:convert';
import 'package:logging/logging.dart';
import 'webkit_inspection_protocol.dart';
/// Forwards a [Stream] to a [WipConnection] and events
/// from a [WipConnection] to a [StreamSink].
class ChromeForwarder {
static final _log = new Logger('ChromeForwarder');
final Stream _in;
final StreamSink _out;
final WipConnection _debugger;
final _subscriptions = <StreamSubscription>[];
final _closedController = new StreamController.broadcast();
factory ChromeForwarder(WipConnection debugger, Stream stream,
[StreamSink sink]) {
if (sink == null) {
sink = stream as StreamSink;
}
return new ChromeForwarder._(debugger, stream, sink);
}
ChromeForwarder._(this._debugger, this._in, this._out) {
_subscriptions.add(_in.listen(_onClientDataHandler,
onError: _onClientErrorHandler, onDone: _onClientDoneHandler));
_subscriptions.add(_debugger.onNotification.listen(_onDebuggerDataHandler,
onError: _onDebuggerErrorHandler, onDone: _onDebuggerDoneHandler));
}
Future _onClientDataHandler(String data) async {
var json = JSON.decode(data);
var response = {'id': json['id']};
_log.info('Forwarding to debugger: $data');
try {
var resp = await _debugger.sendCommand(json['method'], json['params']);
if (resp.result != null) {
response['result'] = resp.result;
}
} on WipError catch (e) {
response['error'] = e.error;
}
_out.add(JSON.encode(response));
}
void _onClientErrorHandler(Object error, StackTrace stackTrace) {
_log.severe('error from forwarded client', error, stackTrace);
}
void _onClientDoneHandler() {
_log.info('forwarded client closed.');
stop();
}
void _onDebuggerDataHandler(WipEvent event) {
_log.info('forwarding event: $event');
var json = {'method': event.method};
if (event.params != null) {
json['params'] = event.params;
}
_out.add(JSON.encode(json));
}
void _onDebuggerErrorHandler(Object error, StackTrace stackTrace) {
_log.severe('error from debugger', error, stackTrace);
}
void _onDebuggerDoneHandler() {
_log.info('debugger closed');
stop();
}
void pause() {
assert(_subscriptions.isNotEmpty);
_log.info('Pausing forwarding');
_subscriptions.forEach((s) => s.pause());
_subscriptions.clear();
}
void resume() {
assert(_subscriptions.isNotEmpty);
_log.info('Resuming forwarding');
_subscriptions.forEach((s) => s.resume());
_subscriptions.clear();
}
Future stop() {
assert(_subscriptions.isNotEmpty);
_log.info('Stopping forwarding');
_subscriptions.forEach((s) => s.cancel());
_subscriptions.clear();
_closedController.add(null);
return Future.wait([_closedController.close(), _out.close()]);
}
Stream get onClosed => _closedController.stream;
}