pollForResponse function

Future<BinaryBlob> pollForResponse(
  1. Agent agent,
  2. Principal canisterId,
  3. RequestId requestId,
  4. PollStrategy strategy,
  5. String method, {
  6. BinaryBlob? overrideCertificate,
})

Implementation

Future<BinaryBlob> pollForResponse(
  Agent agent,
  Principal canisterId,
  RequestId requestId,
  PollStrategy strategy,
  String method, {
  BinaryBlob? overrideCertificate,
}) async {
  final Principal? caller;
  if (agent is HttpAgent) {
    caller = agent.identity?.getPrincipal();
  } else {
    caller = null;
  }

  final path = [blobFromText('request_status'), requestId];
  final Certificate cert;
  if (overrideCertificate != null) {
    cert = Certificate(
      cert: overrideCertificate,
      canisterId: canisterId,
      rootKey: agent.rootKey,
    );
  } else {
    final state = await agent.readState(
      canisterId,
      ReadStateOptions(paths: [path]),
      null,
    );
    cert = Certificate(
      cert: state.certificate,
      canisterId: canisterId,
      rootKey: agent.rootKey,
    );
  }
  final verified = await cert.verify();
  if (!verified) {
    throw UnverifiedCertificateError();
  }

  final maybeBuf = cert.lookup([...path, blobFromText('status').buffer]);
  final RequestStatusResponseStatus status;
  if (maybeBuf == null) {
    // Missing requestId means we need to wait.
    status = RequestStatusResponseStatus.unknown;
  } else {
    status = RequestStatusResponseStatus.fromName(maybeBuf.u8aToString());
  }

  switch (status) {
    case RequestStatusResponseStatus.replied:
      return cert.lookup([...path, blobFromText('reply')]) as BinaryBlob;
    case RequestStatusResponseStatus.received:
    case RequestStatusResponseStatus.unknown:
    case RequestStatusResponseStatus.processing:
      // Execute the polling strategy, then retry.
      await strategy(canisterId, requestId, status);
      // Passing the override certificate will cause infinite stacks.
      return pollForResponse(agent, canisterId, requestId, strategy, method);
    case RequestStatusResponseStatus.rejected:
      final rejectCode = cert.lookup(
        [...path, blobFromText('reject_code')],
      )!.toBn();
      final rejectMessage = cert.lookup(
        [...path, blobFromText('reject_message')],
      )!.u8aToString();
      throw PollingResponseRejectedException(
        canisterId: canisterId,
        requestId: requestIdToHex(requestId),
        status: status,
        method: method,
        rejectCode: rejectCode,
        rejectMessage: rejectMessage,
        caller: caller,
      );
    case RequestStatusResponseStatus.done:
      // This is _technically_ not an error, but we still didn't see the
      // `Replied` status so we don't know the result and cannot decode it.
      throw PollingResponseNoReplyException(
        canisterId: canisterId,
        requestId: requestIdToHex(requestId),
        status: status,
        method: method,
        caller: caller,
      );
  }
}