11import 'dart:convert' ;
22import 'dart:typed_data' ;
33
4+ import 'package:typed_data/typed_data.dart' ;
5+
46import '../candid/idl.dart' ;
57import '../principal/principal.dart' ;
68import 'agent/api.dart' ;
9+ import 'agent/http/types.dart' ;
710import 'canisters/management.dart' ;
11+ import 'cbor.dart' as cbor;
812import 'errors.dart' ;
913import 'polling/polling.dart' ;
1014import 'request_id.dart' ;
@@ -72,6 +76,7 @@ class CallConfig {
7276 this .pollingStrategyFactory,
7377 this .canisterId,
7478 this .effectiveCanisterId,
79+ this .callSync = true ,
7580 });
7681
7782 factory CallConfig .fromJson (Map <String , dynamic > map) {
@@ -80,6 +85,7 @@ class CallConfig {
8085 pollingStrategyFactory: map['pollingStrategyFactory' ],
8186 canisterId: map['canisterId' ],
8287 effectiveCanisterId: map['effectiveCanisterId' ],
88+ callSync: map['callSync' ] ?? true ,
8389 );
8490 }
8591
@@ -97,12 +103,16 @@ class CallConfig {
97103 /// The effective canister ID. This should almost always be ignored.
98104 final Principal ? effectiveCanisterId;
99105
106+ /// Whether to call the endpoint synchronously.
107+ final bool callSync;
108+
100109 Map <String , dynamic > toJson () {
101110 return {
102111 'agent' : agent,
103112 'pollingStrategyFactory' : pollingStrategyFactory,
104113 'canisterId' : canisterId,
105114 'effectiveCanisterId' : effectiveCanisterId,
115+ 'callSync' : callSync,
106116 };
107117 }
108118}
@@ -114,6 +124,7 @@ class ActorConfig extends CallConfig {
114124 super .pollingStrategyFactory,
115125 super .canisterId,
116126 super .effectiveCanisterId,
127+ super .callSync,
117128 this .callTransform,
118129 this .queryTransform,
119130 });
@@ -126,6 +137,7 @@ class ActorConfig extends CallConfig {
126137 pollingStrategyFactory: map['pollingStrategyFactory' ],
127138 canisterId: map['canisterId' ],
128139 effectiveCanisterId: map['effectiveCanisterId' ],
140+ callSync: map['callSync' ] ?? true ,
129141 );
130142 }
131143
@@ -411,13 +423,15 @@ ActorMethod _createActorMethod(Actor actor, String methodName, Func func) {
411423 final ecid = effectiveCanisterId != null
412424 ? Principal .from (effectiveCanisterId)
413425 : cid;
414- // final { requestId, response } =
415- final result = await agent! .call (
426+ final callSync = actor.metadata.config? .callSync ?? newOptions.callSync;
427+
428+ final result = await agent! .callRequest (
416429 cid,
417430 CallOptions (
418431 methodName: methodName,
419432 arg: arg,
420433 effectiveCanisterId: ecid,
434+ callSync: callSync,
421435 ),
422436 null ,
423437 );
@@ -428,13 +442,25 @@ ActorMethod _createActorMethod(Actor actor, String methodName, Func func) {
428442 throw UpdateCallRejectedError (cid, methodName, result, requestId);
429443 }
430444
445+ BinaryBlob ? certificate;
446+ // Fall back to polling if we receive an "Accepted" response code,
447+ // otherwise decode the certificate instantly.
448+ if (result is CallResponseBody && result.response? .status != 202 ) {
449+ final buffer = (result.response as HttpResponseBody ).arrayBuffer! ;
450+ final decoded = cbor.cborDecode <Map >(buffer);
451+ certificate = blobFromBuffer (
452+ (decoded['certificate' ] as Uint8Buffer ).buffer,
453+ );
454+ }
455+
431456 final pollStrategy = pollingStrategyFactory ();
432457 final responseBytes = await pollForResponse (
433458 agent,
434459 ecid,
435460 requestId,
436461 pollStrategy,
437462 methodName,
463+ overrideCertificate: certificate,
438464 );
439465
440466 if (responseBytes.isNotEmpty) {
0 commit comments