Commit c0d3351b authored by Steven Allen's avatar Steven Allen

revert interface changes and add options

Instead of changing the existing constructors, add a new DHT constructor that
takes options (and add DHT options).
parent 3befc403
......@@ -10,9 +10,9 @@ import (
"sync"
"time"
opts "github.com/libp2p/go-libp2p-kad-dht/opts"
pb "github.com/libp2p/go-libp2p-kad-dht/pb"
providers "github.com/libp2p/go-libp2p-kad-dht/providers"
routing "github.com/libp2p/go-libp2p-routing"
proto "github.com/gogo/protobuf/proto"
cid "github.com/ipfs/go-cid"
......@@ -28,6 +28,7 @@ import (
protocol "github.com/libp2p/go-libp2p-protocol"
record "github.com/libp2p/go-libp2p-record"
recpb "github.com/libp2p/go-libp2p-record/pb"
routing "github.com/libp2p/go-libp2p-routing"
base32 "github.com/whyrusleeping/base32"
)
......@@ -65,24 +66,13 @@ type IpfsDHT struct {
plk sync.Mutex
}
// NewDHT creates a new DHT object with the given peer as the 'local' host.
// IpfsDHT's initialized with this function will respond to DHT requests,
// whereas IpfsDHT's initialized with NewDHTClient will not.
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching, validator record.Validator) *IpfsDHT {
dht := NewDHTClient(ctx, h, dstore, validator)
h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)
return dht
}
// NewDHTClient creates a new DHT object with the given peer as the 'local'
// host. IpfsDHT clients initialized with this function will not respond to DHT
// requests. If you need a peer to respond to DHT requests, use NewDHT instead.
// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching, validator record.Validator) *IpfsDHT {
dht := makeDHT(ctx, h, dstore)
// New creates a new DHT with the specified host and options.
func New(ctx context.Context, h host.Host, options ...opts.Option) (*IpfsDHT, error) {
var cfg opts.Options
if err := cfg.Apply(append([]opts.Option{opts.Defaults}, options...)...); err != nil {
return nil, err
}
dht := makeDHT(ctx, h, cfg.Datastore)
// register for network notifs.
dht.host.Network().Notify((*netNotifiee)(dht))
......@@ -94,8 +84,35 @@ func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching, validato
})
dht.proc.AddChild(dht.providers.Process())
dht.Validator = validator
dht.Validator = cfg.Validator
if !cfg.Client {
h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)
}
return dht, nil
}
// NewDHT creates a new DHT object with the given peer as the 'local' host.
// IpfsDHT's initialized with this function will respond to DHT requests,
// whereas IpfsDHT's initialized with NewDHTClient will not.
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
dht, err := New(ctx, h, opts.Datastore(dstore))
if err != nil {
panic(err)
}
return dht
}
// NewDHTClient creates a new DHT object with the given peer as the 'local'
// host. IpfsDHT clients initialized with this function will not respond to DHT
// requests. If you need a peer to respond to DHT requests, use NewDHT instead.
// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
dht, err := New(ctx, h, opts.Datastore(dstore), opts.Client(true))
if err != nil {
panic(err)
}
return dht
}
......
......@@ -11,11 +11,10 @@ import (
"testing"
"time"
opts "github.com/libp2p/go-libp2p-kad-dht/opts"
pb "github.com/libp2p/go-libp2p-kad-dht/pb"
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
u "github.com/ipfs/go-ipfs-util"
kb "github.com/libp2p/go-libp2p-kbucket"
netutil "github.com/libp2p/go-libp2p-netutil"
......@@ -72,18 +71,15 @@ func (testValidator) Validate(_ string, b []byte) error {
}
func setupDHT(ctx context.Context, t *testing.T, client bool) *IpfsDHT {
h := bhost.New(netutil.GenSwarmNetwork(t, ctx))
dss := dssync.MutexWrap(ds.NewMapDatastore())
var d *IpfsDHT
validator := record.NamespacedValidator{
"v": blankValidator{},
"pk": record.PublicKeyValidator{},
}
if client {
d = NewDHTClient(ctx, h, dss, validator)
} else {
d = NewDHT(ctx, h, dss, validator)
d, err := New(
ctx,
bhost.New(netutil.GenSwarmNetwork(t, ctx)),
opts.Client(client),
opts.NamespacedValidator("v", blankValidator{}),
)
if err != nil {
t.Fatal(err)
}
return d
}
......
......@@ -8,8 +8,6 @@ import (
"time"
ggio "github.com/gogo/protobuf/io"
ds "github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
u "github.com/ipfs/go-ipfs-util"
pb "github.com/libp2p/go-libp2p-kad-dht/pb"
inet "github.com/libp2p/go-libp2p-net"
......@@ -31,8 +29,10 @@ func TestGetFailures(t *testing.T) {
}
hosts := mn.Hosts()
tsds := dssync.MutexWrap(ds.NewMapDatastore())
d := NewDHT(ctx, hosts[0], tsds, record.NamespacedValidator{})
d, err := New(ctx, hosts[0])
if err != nil {
t.Fatal(err)
}
d.Update(ctx, hosts[1].ID())
// Reply with failures to every message
......@@ -148,8 +148,10 @@ func TestNotFound(t *testing.T) {
t.Fatal(err)
}
hosts := mn.Hosts()
tsds := dssync.MutexWrap(ds.NewMapDatastore())
d := NewDHT(ctx, hosts[0], tsds, record.NamespacedValidator{})
d, err := New(ctx, hosts[0])
if err != nil {
t.Fatal(err)
}
for _, p := range hosts {
d.Update(ctx, p.ID())
......@@ -225,8 +227,10 @@ func TestLessThanKResponses(t *testing.T) {
}
hosts := mn.Hosts()
tsds := dssync.MutexWrap(ds.NewMapDatastore())
d := NewDHT(ctx, hosts[0], tsds, record.NamespacedValidator{})
d, err := New(ctx, hosts[0])
if err != nil {
t.Fatal(err)
}
for i := 1; i < 5; i++ {
d.Update(ctx, hosts[i].ID())
......@@ -292,8 +296,10 @@ func TestMultipleQueries(t *testing.T) {
t.Fatal(err)
}
hosts := mn.Hosts()
tsds := dssync.MutexWrap(ds.NewMapDatastore())
d := NewDHT(ctx, hosts[0], tsds, record.NamespacedValidator{})
d, err := New(ctx, hosts[0])
if err != nil {
t.Fatal(err)
}
d.Update(ctx, hosts[1].ID())
......
package dhtopts
import (
"fmt"
ds "github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
record "github.com/libp2p/go-libp2p-record"
)
// Options is a structure containing all the options that can be used when constructing a DHT.
type Options struct {
Datastore ds.Batching
Validator record.Validator
Client bool
}
// Apply applies the given options to this Option
func (o *Options) Apply(opts ...Option) error {
for i, opt := range opts {
if err := opt(o); err != nil {
return fmt.Errorf("dht option %d failed: %s", i, err)
}
}
return nil
}
// Option DHT option type.
type Option func(*Options) error
// Defaults are the default DHT options. This option will be automatically
// prepended to any options you pass to the DHT constructor.
var Defaults = func(o *Options) error {
o.Validator = record.NamespacedValidator{
"pk": record.PublicKeyValidator{},
}
o.Datastore = dssync.MutexWrap(ds.NewMapDatastore())
return nil
}
// Datastore configures the DHT to use the specified datastore.
//
// Defaults to an in-memory (temporary) map.
func Datastore(ds ds.Batching) Option {
return func(o *Options) error {
o.Datastore = ds
return nil
}
}
// Client configures whether or not the DHT operates in client-only mode.
//
// Defaults to false.
func Client(only bool) Option {
return func(o *Options) error {
o.Client = only
return nil
}
}
// Validator configures the DHT to use the specified validator.
//
// Defaults to a namespaced validator that can only validate public keys.
func Validator(v record.Validator) Option {
return func(o *Options) error {
o.Validator = v
return nil
}
}
// NamespacedValidator adds a validator namespaced under `ns`. This option fails
// if the DHT is not using a `record.NamespacedValidator` as it's validator (it
// uses one by default but this can be overridden with the `Validator` option).
//
// Example: Given a validator registered as `NamespacedValidator("ipns",
// myValidator)`, all records with keys starting with `/ipns/` will be validated
// with `myValidator`.
func NamespacedValidator(ns string, v record.Validator) Option {
return func(o *Options) error {
nsval, ok := o.Validator.(record.NamespacedValidator)
if !ok {
return fmt.Errorf("can only add namespaced validators to a NamespacedValidator")
}
nsval[ns] = v
return nil
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment