dvWorkerHandle function

Future<void> dvWorkerHandle(
  1. Map<Object?, Object?> request,
  2. void post(
    1. Map<String, Object?> message
    )
)

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,
  });
}