diff --git a/main.go b/main.go index d86f6ec..b05f6a2 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import "gopkg.in/hlandau/service.v2" import "gopkg.in/hlandau/easyconfig.v1" import "github.com/hlandau/ncdns/server" +import "github.com/hlandau/degoutils/xlogconfig" import "path/filepath" func main() { @@ -12,6 +13,7 @@ func main() { ProgramName: "ncdns", } config.ParseFatal(&cfg) + xlogconfig.Init() // We use the configPath to resolve paths relative to the config file. cfg.ConfigDir = filepath.Dir(config.ConfigFilePath()) diff --git a/namecoin/namecoin.go b/namecoin/namecoin.go index 535753a..f5a033b 100644 --- a/namecoin/namecoin.go +++ b/namecoin/namecoin.go @@ -12,6 +12,7 @@ import "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. @@ -159,4 +160,32 @@ func (nc *Conn) Filter(regexp string, maxage, from, count int) (names []extratyp 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 := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, 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") +} + // © 2014 Hugo Landau GPLv3 or later diff --git a/ncdumpzone/ncdumpzone.go b/ncdumpzone/ncdumpzone.go new file mode 100644 index 0000000..41ea34e --- /dev/null +++ b/ncdumpzone/ncdumpzone.go @@ -0,0 +1,88 @@ +package main + +import "gopkg.in/alecthomas/kingpin.v2" +import "github.com/hlandau/ncdns/ncdomain" +import "github.com/hlandau/ncdns/namecoin" +import "github.com/hlandau/ncdns/util" +import "github.com/hlandau/xlog" +import "strings" +import "fmt" + +var log, Log = xlog.New("ncdumpzone") + +var ( + rpchostFlag = kingpin.Flag("rpchost", "Namecoin RPC host:port").Default("127.0.0.1:8336").String() + rpcuserFlag = kingpin.Flag("rpcuser", "Namecoin RPC username").String() + rpcpassFlag = kingpin.Flag("rpcpass", "Namecoin RPC password").String() +) + +var conn namecoin.Conn + +const perCall = 1000 + +func main() { + kingpin.Parse() + + conn.Server = *rpchostFlag + conn.Username = *rpcuserFlag + conn.Password = *rpcpassFlag + + var errors []error + errFunc := func(err error, isWarning bool) { + errors = append(errors, err) + } + + getNameFunc := func(k string) (string, error) { + return conn.Query(k) + } + + currentName := "d/" + continuing := 0 + + for { + results, err := conn.Scan(currentName, perCall) + log.Fatale(err, "scan") + + if len(results) <= continuing { + log.Info("out of results, stopping") + break + } + + // scan is [x,y] not (x,y], so exclude the first result + if continuing != 0 { + results = results[1:] + } else { + continuing = 1 + } + + for i := range results { + r := &results[i] + + // The order in which name_scan returns results is seemingly rather + // random, so we can't stop when we see a non-d/ name, so just skip it. + if !strings.HasPrefix(r.Name, "d/") { + continue + } + + suffix, err := util.NamecoinKeyToBasename(r.Name) + if err != nil { + continue + } + + errors = errors[0:0] + value := ncdomain.ParseValue(r.Name, r.Value, getNameFunc, errFunc) + if len(errors) > 0 { + continue + } + + rrs, err := value.RRsRecursive(nil, suffix+".bit.", "bit.") + log.Warne(err, "error generating RRs") + + for _, rr := range rrs { + fmt.Print(rr.String(), "\n") + } + } + + currentName = results[len(results)-1].Name + } +}