Skip to content

Commit

Permalink
Add call endpoint.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Feb 28, 2022
1 parent 673fb33 commit 0bfb478
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 18 deletions.
83 changes: 80 additions & 3 deletions agent.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package agent

import (
"encoding/binary"
"fmt"
"net/url"
"time"
Expand Down Expand Up @@ -42,6 +43,32 @@ func New(cfg AgentConfig) Agent {
}
}

func (a Agent) Call(canisterID principal.Principal, methodName string, args []byte) (string, error) {
types, values, err := a.CallCandid(canisterID, methodName, args)
if err != nil {
return "", err
}
return candid.DecodeValues(types, values)
}

func (a Agent) CallCandid(canisterID principal.Principal, methodName string, args []byte) ([]idl.Type, []interface{}, error) {
requestID, data, err := a.sign(Request{
Type: RequestTypeCall,
Sender: a.Sender(),
CanisterID: canisterID,
MethodName: methodName,
Arguments: args,
IngressExpiry: a.expiryDate(),
})
if err != nil {
return nil, nil, err
}
if _, err := a.call(canisterID, data); err != nil {
return nil, nil, err
}
return a.poll(canisterID, *requestID, time.Second, time.Second*10)
}

func (a Agent) GetCanisterControllers(canisterID principal.Principal) ([]principal.Principal, error) {
resp, err := a.GetCanisterInfo(canisterID, "controllers")
if err != nil {
Expand Down Expand Up @@ -109,21 +136,71 @@ func (a Agent) QueryCandid(canisterID principal.Principal, methodName string, ar
}
}

func (agent *Agent) RequestStatus(canisterID principal.Principal, requestID RequestID) ([]byte, cert.Node, error) {
path := [][]byte{[]byte("request_status"), requestID[:]}
c, err := agent.readStateCertificate(canisterID, [][][]byte{path})
if err != nil {
return nil, nil, err
}
var state map[string]interface{}
if err := cbor.Unmarshal(c, &state); err != nil {
return nil, nil, err
}
node, err := cert.DeserializeNode(state["tree"].([]interface{}))
if err != nil {
return nil, nil, err
}
return cert.Lookup(append(path, []byte("status")), node), node, nil
}

func (a Agent) Sender() principal.Principal {
return a.identity.Sender()
}

func (agent *Agent) call(canisterID principal.Principal, data []byte) ([]byte, error) {
return agent.client.call(canisterID, data)
}

func (a Agent) expiryDate() uint64 {
return uint64(time.Now().Add(a.ingressExpiry).UnixNano())
}

func (a Agent) query(canisterID principal.Principal, data []byte) (*QueryResponse, error) {
func (a Agent) poll(canisterID principal.Principal, requestID RequestID, delay, timeout time.Duration) ([]idl.Type, []interface{}, error) {
ticker := time.NewTicker(delay)
timer := time.NewTimer(timeout)
for {
select {
case <-ticker.C:
data, node, err := a.RequestStatus(canisterID, requestID)
if err != nil {
return nil, nil, err
}
if len(data) != 0 {
path := [][]byte{[]byte("request_status"), requestID[:]}
switch string(data) {
case "rejected":
code := cert.Lookup(append(path, []byte("reject_code")), node)
reject_message := cert.Lookup(append(path, []byte("reject_message")), node)
return nil, nil, fmt.Errorf("(%d) %s", binary.BigEndian.Uint64(code), string(reject_message))
case "replied":
path := [][]byte{[]byte("request_status"), requestID[:]}
reply := cert.Lookup(append(path, []byte("reply")), node)
return idl.Decode(reply)
}
}
case <-timer.C:
return nil, nil, fmt.Errorf("out of time... waited %d seconds", timeout/time.Second)
}
}
}

func (a Agent) query(canisterID principal.Principal, data []byte) (*Response, error) {
resp, err := a.client.query(canisterID, data)
if err != nil {
return nil, err
}
queryReponse := new(QueryResponse)
return queryReponse, cbor.Unmarshal(resp, &queryReponse)
queryReponse := new(Response)
return queryReponse, cbor.Unmarshal(resp, queryReponse)
}

func (a Agent) readState(canisterID principal.Principal, data []byte) (map[string][]byte, error) {
Expand Down
32 changes: 21 additions & 11 deletions dfx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

func TestLocalReplica(t *testing.T) {
if _, err := exec.LookPath("dfx"); err != nil {
t.Skip()
t.Skip("DFX not installed.")
return
}

Expand All @@ -35,16 +35,6 @@ func TestLocalReplica(t *testing.T) {
Host: ic0,
},
})
{
args, _ := candid.EncodeValue("()")
resp, err := agent.Query(canister, "get", args)
if err != nil {
t.Fatal(err)
}
if resp != "(0 : nat)" {
t.Error(resp)
}
}
{
ps, err := agent.GetCanisterControllers(canister)
if err != nil {
Expand All @@ -66,6 +56,26 @@ func TestLocalReplica(t *testing.T) {
t.Error(h)
}
}
{
args, _ := candid.EncodeValue("()")
resp, err := agent.Query(canister, "get", args)
if err != nil {
t.Fatal(err)
}
if resp != "(0 : nat)" {
t.Error(resp)
}
}
{
args, _ := candid.EncodeValue("( 1 : nat )")
resp, err := agent.Call(canister, "add", args)
if err != nil {
t.Fatal(err)
}
if resp != "(1 : nat)" {
t.Error(resp)
}
}
}

func startDFX(t *testing.T) *exec.Cmd {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.17

require (
github.com/aviate-labs/candid-go v0.0.0-20220207081439-95cecca37dcd
github.com/aviate-labs/certificate-go v0.0.2-0.20220227153822-3ce38b25fec0
github.com/aviate-labs/certificate-go v0.0.2
github.com/aviate-labs/leb128 v0.3.0
github.com/aviate-labs/principal-go v0.2.0
github.com/fxamacker/cbor/v2 v2.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/aviate-labs/candid-go v0.0.0-20220207081439-95cecca37dcd h1:7dyRw30pv6ob7Mldv5jHshl/G95TNTfGSO6ka0cFMtM=
github.com/aviate-labs/candid-go v0.0.0-20220207081439-95cecca37dcd/go.mod h1:aSwDlnrwlxvHK7v/LfyAI5dCR4CHf5vHfwn/t9xQzgY=
github.com/aviate-labs/certificate-go v0.0.2-0.20220227153822-3ce38b25fec0 h1:eoCN/x6FLtgSc9RoYdXcobgnJYJR0cdQADfxAVIfMAk=
github.com/aviate-labs/certificate-go v0.0.2-0.20220227153822-3ce38b25fec0/go.mod h1:O4CwO5bBe+AFpMLGEz7ZgrMms6V3fJ69d3jb+fpe31g=
github.com/aviate-labs/certificate-go v0.0.2 h1:eohRSsYdANL9n/nykibVO9X0NfyAGl3e5wBcZXBYSqo=
github.com/aviate-labs/certificate-go v0.0.2/go.mod h1:O4CwO5bBe+AFpMLGEz7ZgrMms6V3fJ69d3jb+fpe31g=
github.com/aviate-labs/leb128 v0.3.0 h1:s9htRv3OYk8nuHqJu9PiVFJxv1jIUTIcpEeiURa91uQ=
github.com/aviate-labs/leb128 v0.3.0/go.mod h1:GclhBOjhIKmcDlgHKhj0AEZollzERfZUbcRUKiQVqgY=
github.com/aviate-labs/principal-go v0.2.0 h1:Xp5V9L90dCmOLsUjTwL96Yhrv4czOSyzMV8fzJunmuM=
Expand Down
2 changes: 1 addition & 1 deletion responses.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package agent

type QueryResponse struct {
type Response struct {
Status string `cbor:"status"`
Reply map[string][]byte `cbor:"reply"`
RejectCode uint64 `cbor:"reject_code"`
Expand Down

0 comments on commit 0bfb478

Please sign in to comment.