blob: 84ff5606b541c347e29fe3b533c301fb361b1573 [file] [log] [blame]
// 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';
import 'package:async/async.dart';
import 'package:stream_channel/stream_channel.dart';
import '../util/dart.dart' as dart;
import "../util/remote_exception.dart";
/// Spawns a hybrid isolate from [url] with the given [message], and returns a
/// [StreamChannel] that communicates with it.
///
/// This connects the main isolate to the hybrid isolate, whereas
/// `lib/src/frontend/spawn_hybrid.dart` connects the test isolate to the main
/// isolate.
StreamChannel spawnHybridUri(String url, Object message) {
return StreamChannelCompleter.fromFuture(() async {
var port = new ReceivePort();
var onExitPort = new ReceivePort();
try {
var code = """
import "package:test/src/runner/hybrid_listener.dart";
import "${url.replaceAll(r'$', '%24')}" as lib;
void main(_, List data) => listen(() => lib.hybridMain, data);
""";
var isolate = await dart.runInIsolate(code, [port.sendPort, message],
onExit: onExitPort.sendPort);
// Ensure that we close [port] and [channel] when the isolate exits.
var disconnector = new Disconnector();
onExitPort.listen((_) {
disconnector.disconnect();
onExitPort.close();
});
return new IsolateChannel.connectReceive(port)
.transform(disconnector)
.transformSink(
new StreamSinkTransformer.fromHandlers(handleDone: (sink) {
// If the user closes the stream channel, kill the isolate.
isolate.kill();
onExitPort.close();
sink.close();
}));
} catch (error, stackTrace) {
port.close();
onExitPort.close();
// Make sure any errors in spawning the isolate are forwarded to the test.
return new StreamChannel(
new Stream.fromFuture(new Future.value({
"type": "error",
"error": RemoteException.serialize(error, stackTrace)
})),
new NullStreamSink());
}
}());
}