forked from TrueCloudLab/certificates
104 lines
3.1 KiB
Go
104 lines
3.1 KiB
Go
package acme
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
)
|
|
|
|
// multiSchemeClient unites invoker.RPCInvoke and common interface of
|
|
// rpcclient.Client and rpcclient.WSClient.
|
|
type multiSchemeClient interface {
|
|
invoker.RPCInvoke
|
|
// Init turns client to "ready-to-work" state.
|
|
Init() error
|
|
// Close closes connections.
|
|
Close()
|
|
// GetContractStateByID returns state of the NNS contract on 1 input.
|
|
GetContractStateByID(int32) (*state.Contract, error)
|
|
}
|
|
|
|
// NNS is used to interact with NNS contract.
|
|
// Before work, the connection to the NNS server must be established using Dial method.
|
|
type NNS struct {
|
|
nnsContract util.Uint160
|
|
client multiSchemeClient
|
|
}
|
|
|
|
// Dial connects to the address of the NNS server.
|
|
// If URL address scheme is 'ws' or 'wss', then WebSocket protocol is used, otherwise HTTP.
|
|
func (n *NNS) Dial(address string) error {
|
|
var err error
|
|
|
|
uri, err := url.Parse(address)
|
|
if err == nil && (uri.Scheme == "ws" || uri.Scheme == "wss") {
|
|
n.client, err = rpcclient.NewWS(context.Background(), address, rpcclient.WSOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("create Neo WebSocket client: %w", err)
|
|
}
|
|
} else {
|
|
n.client, err = rpcclient.New(context.Background(), address, rpcclient.Options{})
|
|
if err != nil {
|
|
return fmt.Errorf("create Neo HTTP client: %w", err)
|
|
}
|
|
}
|
|
|
|
if err = n.client.Init(); err != nil {
|
|
return fmt.Errorf("initialize Neo client: %w", err)
|
|
}
|
|
|
|
nnsContract, err := n.client.GetContractStateByID(1)
|
|
if err != nil {
|
|
return fmt.Errorf("get NNS contract state: %w", err)
|
|
}
|
|
|
|
n.nnsContract = nnsContract.Hash
|
|
|
|
return nil
|
|
}
|
|
|
|
// Close closes connections of multiSchemeClient.
|
|
func (n *NNS) Close() {
|
|
n.client.Close()
|
|
}
|
|
|
|
// GetTXTRecords returns TXT records of the provided domain by calling `getRecords` method of NNS contract.
|
|
func (n *NNS) GetTXTRecords(name string) ([]string, error) {
|
|
params, err := smartcontract.NewParametersFromValues(name, int64(nns.TXT))
|
|
if err != nil {
|
|
return make([]string, 0), fmt.Errorf("create slice of params: %w", err)
|
|
}
|
|
item, err := unwrap.Item(n.client.InvokeFunction(n.nnsContract, "getRecords", params, nil))
|
|
if err != nil {
|
|
return make([]string, 0), fmt.Errorf("contract invocation: %w", err)
|
|
}
|
|
|
|
if _, ok := item.(stackitem.Null); !ok {
|
|
arr, ok := item.Value().([]stackitem.Item)
|
|
if !ok {
|
|
return make([]string, 0), errors.New("invalid cast to stack item slice")
|
|
}
|
|
|
|
var result = make([]string, 0, len(arr))
|
|
for i := range arr {
|
|
recordValue, err := arr[i].TryBytes()
|
|
if err != nil {
|
|
return make([]string, 0), fmt.Errorf("convert array item to byte slice: %w", err)
|
|
}
|
|
result = append(result, string(recordValue))
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
return make([]string, 0), errors.New("records not found")
|
|
}
|