Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

Commit

Permalink
Merge pull request #21 from libp2p/feat/getvalue
Browse files Browse the repository at this point in the history
make routing less DHT specific
  • Loading branch information
Stebalien authored Jun 2, 2018
2 parents cfa74f6 + 31edb3d commit c131f85
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .gx/lastpubver
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.22: QmZix3EdeAdc4wnRksRXWEQ6kbqiFAP16h3Sq9JnEiP71N
2.3.0: QmUHRKTeaoASDvDj7cTAXsmjAY7KQ13ErtzkQHZQq6uFUz
50 changes: 50 additions & 0 deletions options/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ropts

// Option is a single routing option.
type Option func(opts *Options) error

// Options is a set of routing options
type Options struct {
// Allow expired values.
Expired bool
Offline bool
// Other (ValueStore implementation specific) options.
Other map[interface{}]interface{}
}

// Apply applies the given options to this Options
func (opts *Options) Apply(options ...Option) error {
for _, o := range options {
if err := o(opts); err != nil {
return err
}
}
return nil
}

// ToOption converts this Options to a single Option.
func (opts *Options) ToOption() Option {
return func(nopts *Options) error {
*nopts = *opts
if opts.Other != nil {
nopts.Other = make(map[interface{}]interface{}, len(opts.Other))
for k, v := range opts.Other {
nopts.Other[k] = v
}
}
return nil
}
}

// Expired is an option that tells the routing system to return expired records
// when no newer records are known.
var Expired Option = func(opts *Options) error {
opts.Expired = true
return nil
}

// Offline is an option that tells the routing system to operate offline (i.e., rely on cached/local data only).
var Offline Option = func(opts *Options) error {
opts.Offline = true
return nil
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@
"license": "MIT",
"name": "go-libp2p-routing",
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
"version": "2.2.22"
"version": "2.3.0"
}

78 changes: 46 additions & 32 deletions routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"context"
"errors"

ropts "github.com/libp2p/go-libp2p-routing/options"

cid "github.com/ipfs/go-cid"
ci "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
Expand All @@ -14,6 +16,10 @@ import (
// ErrNotFound is returned when a search fails to find anything
var ErrNotFound = errors.New("routing: not found")

// ErrNotSupported is returned when a search or put fails because the key type
// isn't supported.
var ErrNotSupported = errors.New("routing: operation or key not supported")

// ContentRouting is a value provider layer of indirection. It is used to find
// information about who has what content.
type ContentRouting interface {
Expand All @@ -36,26 +42,23 @@ type PeerRouting interface {
FindPeer(context.Context, peer.ID) (pstore.PeerInfo, error)
}

// ValueStore is a basic Put/Get interface.
type ValueStore interface {
// Basic Put/Get

// PutValue adds value corresponding to given Key.
PutValue(context.Context, string, []byte) error
PutValue(context.Context, string, []byte, ...ropts.Option) error

// GetValue searches for the value corresponding to given Key.
GetValue(context.Context, string) ([]byte, error)
GetValue(context.Context, string, ...ropts.Option) ([]byte, error)

// GetValues searches for values corresponding to given Key.
//
// Passing a value of '0' for the count argument will cause the
// routing interface to return values only from cached or local storage
// and return an error if no cached value is found.
// TODO
// SearchValue searches for better and better values from this value
// store corresponding to the given Key. Implementations may halt the
// search after a period of time or may continue searching indefinitely.
//
// Passing a value of '1' will return a local value if found, and query
// the network for the first value it finds otherwise.
// As a result, a value of '1' is mostly useful for cases where the record
// in question has only one valid value (such as public keys)
GetValues(c context.Context, k string, count int) ([]RecvdVal, error)
// Useful when you want a result *now* but still want to hear about
// better/newer results.
//SearchValue(context.Context, string, ...ropts.Option) (<-chan []byte, error)
}

// IpfsRouting is the combination of different routing types that ipfs
Expand All @@ -73,35 +76,46 @@ type IpfsRouting interface {
// TODO expose io.Closer or plain-old Close error
}

// RecvdVal represents a dht value record that has been received from a given peer
// it is used to track peers with expired records in order to correct them.
type RecvdVal struct {
From peer.ID
Val []byte
}

// PubKeyFetcher is an interfaces that should be implemented by value stores
// that can optimize retrieval of public keys.
//
// TODO(steb): Consider removing, see #22.
type PubKeyFetcher interface {
// GetPublicKey returns the public key for the given peer.
GetPublicKey(context.Context, peer.ID) (ci.PubKey, error)
}

// KeyForPublicKey returns the key used to retrieve public keys
// from the dht.
// from a value store.
func KeyForPublicKey(id peer.ID) string {
return "/pk/" + string(id)
}

func GetPublicKey(r ValueStore, ctx context.Context, pkhash []byte) (ci.PubKey, error) {
// GetPublicKey retrieves the public key associated with the given peer ID from
// the value store.
//
// If the ValueStore is also a PubKeyFetcher, this method will call GetPublicKey
// (which may be better optimized) instead of GetValue.
func GetPublicKey(r ValueStore, ctx context.Context, p peer.ID) (ci.PubKey, error) {
k, err := p.ExtractPublicKey()
if err != nil {
// An error means that the peer ID is invalid.
return nil, err
}
if k != nil {
return k, nil
}

if dht, ok := r.(PubKeyFetcher); ok {
// If we have a DHT as our routing system, use optimized fetcher
return dht.GetPublicKey(ctx, peer.ID(pkhash))
} else {
key := "/pk/" + string(pkhash)
pkval, err := r.GetValue(ctx, key)
if err != nil {
return nil, err
}

// get PublicKey from node.Data
return ci.UnmarshalPublicKey(pkval)
return dht.GetPublicKey(ctx, p)
}
key := KeyForPublicKey(p)
pkval, err := r.GetValue(ctx, key)
if err != nil {
return nil, err
}

// get PublicKey from node.Data
return ci.UnmarshalPublicKey(pkval)
}

0 comments on commit c131f85

Please sign in to comment.