dvWorkerHandle function
Runs one request inside a worker, posting what happens through post.
Always posts a final done or failed, whatever the request looked
like, so a page never waits on a request the worker could not read.
Implementation
Future<void> dvWorkerHandle(
Map<Object?, Object?> request,
void Function(Map<String, Object?> message) post,
) async {
final Object? rawId = request['id'];
final int id = rawId is num ? rawId.toInt() : -1;
final Object? name = request['task'];
void fail(DVWorkerFailureKind kind, String error, [String? stack]) =>
post(<String, Object?>{
'id': id,
'kind': DVWorkerResponseKind.failed.name,
'failure': kind.name,
'error': error,
'stack': stack,
});
if (name is! String) {
fail(DVWorkerFailureKind.crashed, 'the request named no task');
return;
}
final DVWorkerCall<Object?, Object?>? call = DVWorkerTasks.lookup(name);
if (call == null) {
fail(
DVWorkerFailureKind.unsendableTask,
'the worker has no task registered as "$name"; register it with '
'DVWorkerTasks in the worker entry as well as in the page',
);
return;
}
final Object? value;
try {
value = await call.invoke(request['input'], _PostingReporter(id, post));
} on Object catch (error, stackTrace) {
fail(DVWorkerFailureKind.threw, '${error.runtimeType}: $error',
stackTrace.toString());
return;
}
final String? unportable = dvWorkerUnportable(value);
if (unportable != null) {
fail(DVWorkerFailureKind.unsendableResult,
'the result cannot cross back from the worker: $unportable');
return;
}
post(<String, Object?>{
'id': id,
'kind': DVWorkerResponseKind.done.name,
'value': value,
});
}