@ -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