Skip to content
This repository was archived by the owner on Nov 18, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflow/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Dart

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- uses: dart-lang/setup-dart@stable

- name: Install dependencies
run: dart pub get

# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .

# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: dart analyze

# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
- name: Run tests
run: dart test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ pubspec.lock
# Directory created by dartdoc
doc/api/

*.iml
*.iml
.tool-versions
15 changes: 0 additions & 15 deletions .travis.yml

This file was deleted.

18 changes: 4 additions & 14 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
analyzer:
strong-mode: true
# exclude:
# - path/to/excluded/files/**
include: package:lint/analysis_options.yaml

# Lint rules and documentation, see http://dart-lang.github.io/linter/lints
linter:
rules:
- cancel_subscriptions
- hash_and_equals
- iterable_contains_unrelated_type
- list_remove_unrelated_type
- test_types_in_equals
- unrelated_type_equality_checks
- valid_regexps
analyzer:
strong-mode:
implicit-casts: true
19 changes: 0 additions & 19 deletions appveyor.yml

This file was deleted.

4 changes: 2 additions & 2 deletions lib/isolate_executor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
///
library isolate_executor;

export 'src/source_generator.dart';
export 'src/executor.dart';
export 'src/executable.dart';
export 'src/executor.dart';
export 'src/source_generator.dart';
54 changes: 35 additions & 19 deletions lib/src/executable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,46 @@ abstract class Executable<T> {
Future<T> execute();

final Map<String, dynamic> message;
final SendPort _sendPort;

U instanceOf<U>(String typeName,
{List positionalArguments: const [], Map<Symbol, dynamic> namedArguments, Symbol constructorName}) {
ClassMirror typeMirror = currentMirrorSystem().isolate.rootLibrary.declarations[new Symbol(typeName)];
if (typeMirror == null) {
typeMirror = currentMirrorSystem()
.libraries
.values
.where((lib) => lib.uri.scheme == "package" || lib.uri.scheme == "file")
.expand((lib) => lib.declarations.values)
.firstWhere((decl) => decl is ClassMirror && MirrorSystem.getName(decl.simpleName) == typeName,
orElse: () => throw new ArgumentError("Unknown type '$typeName'. Did you forget to import it?"));
}

return typeMirror.newInstance(constructorName ?? const Symbol(""), positionalArguments, namedArguments).reflectee
as U;
final SendPort? _sendPort;

U instanceOf<U>(
String typeName, {
List positionalArguments = const [],
Map<Symbol, dynamic> namedArguments = const {},
Symbol constructorName = const Symbol(""),
}) {
ClassMirror? typeMirror = currentMirrorSystem()
.isolate
.rootLibrary
.declarations[Symbol(typeName)] as ClassMirror?;

typeMirror ??= currentMirrorSystem()
.libraries
.values
.where((lib) => lib.uri.scheme == "package" || lib.uri.scheme == "file")
.expand((lib) => lib.declarations.values)
.firstWhere(
(decl) =>
decl is ClassMirror &&
MirrorSystem.getName(decl.simpleName) == typeName,
orElse: () => throw ArgumentError(
"Unknown type '$typeName'. Did you forget to import it?"),
) as ClassMirror?;

return typeMirror!
.newInstance(
constructorName,
positionalArguments,
namedArguments,
)
.reflectee as U;
}

void send(dynamic message) {
_sendPort.send(message);
_sendPort!.send(message);
}

void log(String message) {
_sendPort.send({"_line_": message});
_sendPort!.send({"_line_": message});
}
}
86 changes: 59 additions & 27 deletions lib/src/executor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,51 @@ import 'dart:async';
import 'dart:io';
import 'dart:isolate';

import 'package:isolate_executor/src/executable.dart';
import 'package:isolate_executor/src/source_generator.dart';
import 'package:conduit_isolate_exec/src/executable.dart';
import 'package:conduit_isolate_exec/src/source_generator.dart';

class IsolateExecutor<U> {
IsolateExecutor(this.generator, {this.packageConfigURI, Map<String, dynamic> message}) : this.message = message ?? {};
IsolateExecutor(
this.generator, {
this.packageConfigURI,
this.message = const {},
});

final SourceGenerator generator;
final Map<String, dynamic> message;
final Uri packageConfigURI;
final Completer completer = new Completer();
final Uri? packageConfigURI;
final Completer completer = Completer();

Stream<dynamic> get events => _eventListener.stream;

Stream<String> get console => _logListener.stream;

final StreamController<String> _logListener = new StreamController<String>();
final StreamController<dynamic> _eventListener = new StreamController<dynamic>();
final StreamController<String> _logListener = StreamController<String>();
final StreamController<dynamic> _eventListener = StreamController<dynamic>();

Future<U> execute() async {
if (packageConfigURI != null && !(new File.fromUri(packageConfigURI).existsSync())) {
throw new StateError("Package file '$packageConfigURI' not found. Run 'pub get' and retry.");
if (packageConfigURI != null &&
!File.fromUri(packageConfigURI!).existsSync()) {
throw StateError(
"Package file '$packageConfigURI' not found. Run 'pub get' and retry.",
);
}

final scriptSource = Uri.encodeComponent(await generator.scriptSource);

var onErrorPort = new ReceivePort()
final onErrorPort = ReceivePort()
..listen((err) async {
if (err is List) {
final stack = new StackTrace.fromString(err.last.replaceAll(scriptSource, ""));
final stack =
StackTrace.fromString(err.last.replaceAll(scriptSource, ""));

completer.completeError(new StateError(err.first), stack);
completer.completeError(StateError(err.first), stack);
} else {
completer.completeError(err);
}
});

var controlPort = new ReceivePort()
final controlPort = ReceivePort()
..listen((results) {
if (results is Map && results.length == 1) {
if (results.containsKey("_result")) {
Expand All @@ -55,13 +63,25 @@ class IsolateExecutor<U> {
try {
message["_sendPort"] = controlPort.sendPort;

final dataUri = Uri.parse("data:application/dart;charset=utf-8,${scriptSource}");
final dataUri = Uri.parse(
"data:application/dart;charset=utf-8,$scriptSource",
);
if (packageConfigURI != null) {
await Isolate.spawnUri(dataUri, [], message,
errorsAreFatal: true, onError: onErrorPort.sendPort, packageConfig: packageConfigURI);
await Isolate.spawnUri(
dataUri,
[],
message,
onError: onErrorPort.sendPort,
packageConfig: packageConfigURI,
);
} else {
await Isolate.spawnUri(dataUri, [], message,
errorsAreFatal: true, onError: onErrorPort.sendPort, automaticPackageResolution: true);
await Isolate.spawnUri(
dataUri,
[],
message,
onError: onErrorPort.sendPort,
automaticPackageResolution: true,
);
}

return await completer.future;
Expand All @@ -73,15 +93,27 @@ class IsolateExecutor<U> {
}
}

static Future<T> run<T>(Executable<T> executable,
{Uri packageConfigURI,
List<String> imports,
String additionalContents,
void eventHandler(dynamic event),
void logHandler(String line),
List<Type> additionalTypes}) async {
final source = new SourceGenerator(executable.runtimeType, imports: imports, additionalContents: additionalContents, additionalTypes: additionalTypes);
var executor = new IsolateExecutor<T>(source, packageConfigURI: packageConfigURI, message: executable.message);
static Future<T> run<T>(
Executable<T> executable, {
List<String> imports = const [],
Uri? packageConfigURI,
String? additionalContents,
List<Type> additionalTypes = const [],
void Function(dynamic event)? eventHandler,
void Function(String line)? logHandler,
}) async {
final source = SourceGenerator(
executable.runtimeType,
imports: imports,
additionalContents: additionalContents,
additionalTypes: additionalTypes,
);

final executor = IsolateExecutor<T>(
source,
packageConfigURI: packageConfigURI,
message: executable.message,
);

if (eventHandler != null) {
executor.events.listen(eventHandler);
Expand Down
Loading