diff --git a/backend/backend.go b/backend/backend.go index 7695e96..eb21a05 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -132,7 +132,7 @@ func (b *Backend) getNamecoinEntryLL(name string) (*domain, error) { log.Info("namecoin query (", name, ") succeeded: ", v) - d, err := b.jsonToDomain(v) + d, err := jsonToDomain(v) if err != nil { log.Infoe(err, "cannot convert JSON to domain") return nil, err @@ -141,13 +141,13 @@ func (b *Backend) getNamecoinEntryLL(name string) (*domain, error) { return d, nil } -func (b *Backend) jsonToDomain(v string) (dd *domain, err error) { +func jsonToDomain(v string) (dd *domain, err error) { d := &domain{} ncv := &ncValue{} err = json.Unmarshal([]byte(v), ncv) if err != nil { - log.Infoe(err, fmt.Sprintf("cannot unmarshal JSON: %+v", v)) + //log.Infoe(err, fmt.Sprintf("cannot unmarshal JSON: %+v", v)) return } diff --git a/main.go b/main.go index e20f1bc..d63b1f5 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import "github.com/hlandau/degoutils/config" + //import "github.com/hlandau/degoutils/log" //import "github.com/hlandau/degoutils/daemon" import "github.com/hlandau/degoutils/service" @@ -19,8 +20,8 @@ func main() { cfg.ConfigDir = filepath.Dir(config.ConfigFilePath()) service.Main(&service.Info{ - Name: "ncdns", - Description: "Namecoin to DNS Daemon", + Name: "ncdns", + Description: "Namecoin to DNS Daemon", DefaultChroot: service.EmptyChrootPath, RunFunc: func(smgr service.Manager) error { s, err := server.NewServer(&cfg) @@ -46,22 +47,6 @@ func main() { return nil }, }) - - /* err := daemon.Init() - log.Fatale(err) - - if cfg.Daemonize { - err := daemon.Daemonize() - log.Fatale(err) - } - - err = daemon.DropPrivileges(cfg.UID, cfg.GID) - log.Fatale(err, "can't drop privileges") - - s, err := server.NewServer(&cfg) - log.Fatale(err) - - s.Run()*/ } // © 2014 Hugo Landau GPLv3 or later diff --git a/namecoin/extratypes/extratypes.go b/namecoin/extratypes/extratypes.go index f750b4a..709c363 100644 --- a/namecoin/extratypes/extratypes.go +++ b/namecoin/extratypes/extratypes.go @@ -4,6 +4,9 @@ package extratypes import "github.com/hlandauf/btcjson" import "encoding/json" +import "fmt" + +// name_show type NameShowCmd struct { id interface{} @@ -50,7 +53,7 @@ type NameShowReply struct { ExpiresIn int `json:"expires_in"` } -func replyParser(m json.RawMessage) (interface{}, error) { +func showReplyParser(m json.RawMessage) (interface{}, error) { nsr := &NameShowReply{} err := json.Unmarshal(m, nsr) if err != nil { @@ -60,8 +63,142 @@ func replyParser(m json.RawMessage) (interface{}, error) { return nsr, nil } +// name_sync + +type NameSyncCmd struct { + id interface{} + BlockHash string `json:"hash"` + Count int + Wait bool +} + +func NewNameSyncCmd(id interface{}, blockHash string, count int, wait bool) (*NameSyncCmd, error) { + return &NameSyncCmd{ + id: id, + BlockHash: blockHash, + Count: count, + Wait: wait, + }, nil +} + +func (c *NameSyncCmd) Id() interface{} { + return c.id +} + +func (c *NameSyncCmd) Method() string { + return "name_sync" +} + +func (c *NameSyncCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + c.BlockHash, + c.Count, + c.Wait, + } + + raw, err := btcjson.NewRawCmd(c.id, c.Method(), params) + if err != nil { + return nil, err + } + + return json.Marshal(raw) +} + +func (c *NameSyncCmd) UnmarshalJSON(b []byte) error { + // We don't need to implement this as we are only ever the client. + panic("not implemented") + return nil +} + +type NameSyncReply []NameSyncEvent +type NameSyncEvent struct { + Type string // "firstupdate" or "update" or "atblock" + + // Used for firstupdate and update. + Name string // "d/example" + Value string // "..." + + // Used for atblock. + BlockHash string // in hex + BlockHeight int +} + +var errMalformed = fmt.Errorf("malformed name_sync event") + +func (e *NameSyncEvent) UnmarshalJSON(data []byte) error { + a := []interface{}{} + err := json.Unmarshal(data, &a) + if err != nil { + return err + } + + if len(a) < 1 { + return errMalformed + } + + eventType, ok := a[0].(string) + if !ok { + return errMalformed + } + + e.Type = eventType + + switch eventType { + case "firstupdate", "update": + if len(a) < 3 { + return errMalformed + } + + k, ok := a[1].(string) + if !ok { + return errMalformed + } + + v, ok := a[2].(string) + if !ok { + return errMalformed + } + + e.Name = k + e.Value = v + + case "atblock": + if len(a) < 3 { + return errMalformed + } + + hash, ok := a[1].(string) + if !ok { + return errMalformed + } + + heightf, ok := a[2].(float64) + if !ok { + return errMalformed + } + + height := int(heightf) + + e.BlockHash = hash + e.BlockHeight = height + } + + return nil +} + +func syncReplyParser(m json.RawMessage) (interface{}, error) { + nsr := NameSyncReply{} + err := json.Unmarshal(m, &nsr) + if err != nil { + return nil, err + } + + return nsr, nil +} + func init() { - btcjson.RegisterCustomCmd("name_show", nil, replyParser, "name_show ") + btcjson.RegisterCustomCmd("name_show", nil, showReplyParser, "name_show ") + btcjson.RegisterCustomCmd("name_sync", nil, syncReplyParser, "name_sync ") } // © 2014 Hugo Landau GPLv3 or later diff --git a/namecoin/namecoin.go b/namecoin/namecoin.go index 6cd7553..7c81f0d 100644 --- a/namecoin/namecoin.go +++ b/namecoin/namecoin.go @@ -60,4 +60,63 @@ func (nc *Conn) Query(name string) (v string, err error) { 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) { + cmd, err := extratypes.NewNameSyncCmd(newID(), hash, count, wait) + 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 { + if r.Error.Code == rpcInvalidAddressOrKey { + return nil, ErrSyncNoSuchBlock + } + 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) { + cmd, err := btcjson.NewGetInfoCmd(newID()) + if err != nil { + return 0, err + } + + r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, 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") +} + // © 2014 Hugo Landau GPLv3 or later diff --git a/server/server.go b/server/server.go index f519e6a..6f4ed5d 100644 --- a/server/server.go +++ b/server/server.go @@ -36,7 +36,7 @@ type ServerConfig struct { SelfName string `default:"" usage:"Canonical name for this nameserver (default: autogenerated psuedo-hostname resolving to SelfIP; SelfIP is not used if this is set)"` SelfIP string `default:"127.127.127.127" usage:"The canonical IP address for this service"` - ConfigDir string // path to interpret filenames relative to + ConfigDir string // path to interpret filenames relative to } func (cfg *ServerConfig) cpath(s string) string { @@ -62,7 +62,7 @@ func NewServer(cfg *ServerConfig) (s *Server, err error) { } ecfg := &madns.EngineConfig{ - Backend: b, + Backend: b, VersionString: "ncdns/" + version, }