Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to rpcclient based on current upstream Conformal #103

Merged
merged 1 commit into from
Oct 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import "time"
// Provides an abstract zone file for the Namecoin .bit TLD.
type Backend struct {
//s *Server
nc namecoin.Conn
nc *namecoin.Client
// caches map keys are stream isolation ID's; items are of type *Domain
caches map[string]*lru.Cache
cacheMutex sync.Mutex
Expand All @@ -29,7 +29,7 @@ var log, Log = xlog.New("ncdns.backend")

// Backend configuration.
type Config struct {
NamecoinConn namecoin.Conn
NamecoinConn *namecoin.Client

// Timeout (in milliseconds) for Namecoin RPC requests
NamecoinTimeout int
Expand Down Expand Up @@ -63,9 +63,6 @@ func New(cfg *Config) (backend *Backend, err error) {

b.cfg = *cfg
b.nc = b.cfg.NamecoinConn
//b.nc.Username = cfg.RPCUsername
//b.nc.Password = cfg.RPCPassword
//b.nc.Server = cfg.RPCAddress

b.caches = make(map[string]*lru.Cache)

Expand Down Expand Up @@ -355,13 +352,13 @@ func (b *Backend) resolveName(name, streamIsolationID string) (jsonValue string,
return fv, nil
}

// The btcjson package has quite a long timeout, far in excess of standard
// The rpcclient package has quite a long timeout, far in excess of standard
// DNS timeouts. We need to return an error response rapidly if we can't
// query the backend. Be generous with the timeout as responses from the
// Namecoin JSON-RPC seem sluggish sometimes.
result := make(chan struct{}, 1)
go func() {
jsonValue, err = b.nc.Query(name, streamIsolationID)
jsonValue, err = b.nc.NameQuery(name, streamIsolationID)
log.Errore(err, "failed to query namecoin")
result <- struct{}{}
}()
Expand Down
223 changes: 29 additions & 194 deletions namecoin/namecoin.go
Original file line number Diff line number Diff line change
@@ -1,220 +1,55 @@
package namecoin

// btcjson had to be modified a bit to get correct error reporting.
import (
extratypes "github.com/hlandau/ncbtcjsontypes"
"github.com/hlandauf/btcjson"
"gopkg.in/hlandau/madns.v2/merr"

"expvar"
"fmt"
"sync/atomic"
)

var cQueryCalls = expvar.NewInt("ncdns.namecoin.numQueryCalls")
var cSyncCalls = expvar.NewInt("ncdns.namecoin.numSyncCalls")
var cFilterCalls = expvar.NewInt("ncdns.namecoin.numFilterCalls")
var cScanCalls = expvar.NewInt("ncdns.namecoin.numScanCalls")
var cCurHeightCalls = expvar.NewInt("ncdns.namecoin.numCurHeightCalls")

// Used for generating IDs for JSON-RPC requests.
var idCounter int32

func newID() int32 {
return atomic.AddInt32(&idCounter, 1)
}

// Used to query a Namecoin JSON-RPC interface. Initialize the struct with a
// username, password, and address (hostname:port).
type Conn struct {
Username string
Password string

// If set, this is called to obtain the username and password instead of
// using the Username and Password fields.
GetAuth func() (username, password string, err error)

Server string
}
"github.com/namecoin/btcd/btcjson"
"github.com/namecoin/btcd/rpcclient"
"gopkg.in/hlandau/madns.v2/merr"

func (nc *Conn) getAuth() (username string, password string, err error) {
if nc.GetAuth == nil {
return nc.Username, nc.Password, nil
}
"github.com/namecoin/ncrpcclient"
)

return nc.GetAuth()
// Client represents an ncrpcclient.Client with an additional DNS-friendly
// convenience wrapper around NameShow.
type Client struct {
*ncrpcclient.Client
}

func (nc *Conn) rpcSend(cmd btcjson.Cmd) (btcjson.Reply, error) {
username, password, err := nc.getAuth()
func New(config *rpcclient.ConnConfig, ntfnHandlers *rpcclient.NotificationHandlers) (*Client, error) {
ncClient, err := ncrpcclient.New(config, ntfnHandlers)
if err != nil {
return btcjson.Reply{}, err
return nil, err
}

return btcjson.RpcSend(username, password, nc.Server, cmd)
return &Client{ncClient}, nil
}

// Query the Namecoin daemon for a Namecoin domain (e.g. d/example).
// If the domain exists, returns the value stored in Namecoin, which should be JSON.
// Note that this will return domain data even if the domain is expired.
func (nc *Conn) Query(name string, streamIsolationID string) (v string, err error) {
cQueryCalls.Add(1)

// NameQuery returns the value of a name. If the name doesn't exist, the error
// returned will be merr.ErrNoSuchDomain.
func (c *Client) NameQuery(name string, streamIsolationID string) (string, error) {
// TODO: Pass stream isolation ID to namecoind, and remove this error
if streamIsolationID != "" {
return "", fmt.Errorf("Stream isolation ID '%s' is not yet passed to namecoind", streamIsolationID)
}

cmd, err := extratypes.NewNameShowCmd(newID(), name)
if err != nil {
//log.Info("NC NEWCMD ", err)
return "", err
}

r, err := nc.rpcSend(cmd)
if err != nil {
return "", err
}

if r.Error != nil {
//log.Info("RPC error: ", r.Error)
if r.Error.Code == -4 {
return "", merr.ErrNoSuchDomain
}
return "", r.Error
}

if r.Result == nil {
//log.Info("NC NILRESULT")
return "", fmt.Errorf("got nil result")
}

if nsr, ok := r.Result.(*extratypes.NameShowReply); ok {
//log.Info("NC OK")
return nsr.Value, nil
}

//log.Info("NC BADREPLY")
return "", fmt.Errorf("bad reply")
}

var ErrSyncNoSuchBlock = fmt.Errorf("no block exists with given hash")

const rpcInvalidAddressOrKey = -5

func (nc *Conn) Sync(hash string, count int, wait bool) ([]extratypes.NameSyncEvent, error) {
cSyncCalls.Add(1)

cmd, err := extratypes.NewNameSyncCmd(newID(), hash, count, wait)
if err != nil {
return nil, err
}

r, err := nc.rpcSend(cmd)
nameData, err := c.NameShow(name)
if err != nil {
return nil, err
}

if r.Error != nil {
if r.Error.Code == rpcInvalidAddressOrKey {
return nil, ErrSyncNoSuchBlock
if jerr, ok := err.(*btcjson.RPCError); ok {
if jerr.Code == btcjson.ErrRPCWallet {
// ErrRPCWallet from name_show indicates that
// the name does not exist.
return "", merr.ErrNoSuchDomain
}
}
return nil, r.Error
}

if r.Result == nil {
return nil, fmt.Errorf("got nil result")
}

if nsr, ok := r.Result.(extratypes.NameSyncReply); ok {
return []extratypes.NameSyncEvent(nsr), nil
}

return nil, fmt.Errorf("bad reply")
}

func (nc *Conn) CurHeight() (int, error) {
cCurHeightCalls.Add(1)

cmd, err := btcjson.NewGetInfoCmd(newID())
if err != nil {
return 0, err
}

r, err := nc.rpcSend(cmd)
if err != nil {
return 0, err
}

if r.Error != nil {
return 0, r.Error
}

if r.Result == nil {
return 0, fmt.Errorf("got nil result")
}

if rep, ok := r.Result.(*btcjson.InfoResult); ok {
return int(rep.Blocks), nil
}

return 0, fmt.Errorf("bad reply")
}

func (nc *Conn) Filter(regexp string, maxage, from, count int) (names []extratypes.NameFilterItem, err error) {
cFilterCalls.Add(1)

cmd, err := extratypes.NewNameFilterCmd(newID(), regexp, maxage, from, count)
if err != nil {
return nil, err
}

r, err := nc.rpcSend(cmd)
if err != nil {
return nil, err
}

if r.Error != nil {
return nil, r.Error
}

if r.Result == nil {
return nil, fmt.Errorf("got nil result")
}

if nsr, ok := r.Result.(extratypes.NameFilterReply); ok {
return []extratypes.NameFilterItem(nsr), nil
}

return nil, fmt.Errorf("bad reply")
}

func (nc *Conn) Scan(from string, count int) (names []extratypes.NameFilterItem, err error) {
cScanCalls.Add(1)

cmd, err := extratypes.NewNameScanCmd(newID(), from, count)
if err != nil {
return nil, err
}

r, err := nc.rpcSend(cmd)
if err != nil {
return nil, err
}

if r.Error != nil {
return nil, r.Error
// Some error besides NXDOMAIN happened; pass that error
// through unaltered.
return "", err
}

if r.Result == nil {
return nil, fmt.Errorf("got nil result")
}
// TODO: check the "value_error" field for errors and report those to the caller.

if nsr, ok := r.Result.(extratypes.NameFilterReply); ok {
return []extratypes.NameFilterItem(nsr), nil
}

return nil, fmt.Errorf("bad reply")
// We got the name data. Return the value.
return nameData.Value, nil
}

// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later
32 changes: 26 additions & 6 deletions ncdt/ncdt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import "fmt"
import "os"
import "strconv"
import "io/ioutil"
import "github.com/namecoin/btcd/rpcclient"
import "github.com/namecoin/ncdns/util"

var rpchost = flag.String("rpchost", "", "Namecoin RPC host:port")
var rpcuser = flag.String("rpcuser", "", "Namecoin RPC username")
var rpcpass = flag.String("rpcpass", "", "Namecoin RPC password")
var conn namecoin.Conn
var rpccookiepath = flag.String("rpccookiepath", "", "Namecoin RPC cookie path (used if password is unspecified)")
var conn *namecoin.Client

func usage() {
fmt.Fprintf(os.Stderr, "Usage: ncdt [options] <d/example> <JSON value> [<d/imported-example> <JSON value> ...]\n")
Expand All @@ -21,6 +23,7 @@ func usage() {
fmt.Fprintf(os.Stderr, " -rpchost=host:port Namecoin RPC server address } only required for RPC retrieval\n")
fmt.Fprintf(os.Stderr, " -rpcuser=username Namecoin RPC username }\n")
fmt.Fprintf(os.Stderr, " -rpcpass=password Namecoin RPC password }\n")
fmt.Fprintf(os.Stderr, " -rpccookiepath=path Namecoin RPC cookie path }\n")
os.Exit(2)
}

Expand All @@ -41,7 +44,7 @@ func translateValue(k, v string) (string, error) {

f = os.NewFile(uintptr(n), "-")
} else if len(v) == 1 {
return conn.Query(k, "")
return conn.NameQuery(k, "")
} else {
f, err = os.Open(v)
}
Expand Down Expand Up @@ -71,9 +74,26 @@ func main() {
usage()
}

conn.Username = *rpcuser
conn.Password = *rpcpass
conn.Server = *rpchost
// Connect to local namecoin core RPC server using HTTP POST mode.
connCfg := &rpcclient.ConnConfig{
Host: *rpchost,
User: *rpcuser,
Pass: *rpcpass,
CookiePath: *rpccookiepath,
HTTPPostMode: true, // Namecoin core only supports HTTP POST mode
DisableTLS: true, // Namecoin core does not provide TLS by default
}

var err error

// Notice the notification parameter is nil since notifications are
// not supported in HTTP POST mode.
conn, err = namecoin.New(connCfg, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating RPC client: %v\n", err)
os.Exit(1)
}
defer conn.Shutdown()

for i := 0; i+1 < len(args); i += 2 {
k := args[i]
Expand All @@ -83,7 +103,7 @@ func main() {
os.Exit(1)
}

v, err := translateValue(k, v)
v, err = translateValue(k, v)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to translate value: %v\n", err)
os.Exit(1)
Expand Down
Loading