178
vendor/github.com/status-im/rendezvous/client.go
generated
vendored
Normal file
178
vendor/github.com/status-im/rendezvous/client.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package rendezvous
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
libp2p "github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
ethv4 "github.com/status-im/go-multiaddr-ethv4"
|
||||
"github.com/status-im/rendezvous/protocol"
|
||||
)
|
||||
|
||||
var logger = log.New("package", "rendezvous/client")
|
||||
|
||||
func NewEphemeral() (c Client, err error) {
|
||||
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.Secp256k1, 0, rand.Reader) // bits are ignored with edwards or secp251k1
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
return New(priv)
|
||||
}
|
||||
|
||||
func New(identity crypto.PrivKey) (c Client, err error) {
|
||||
opts := []libp2p.Option{
|
||||
libp2p.Identity(identity),
|
||||
}
|
||||
h, err := libp2p.New(opts...)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
return Client{
|
||||
h: h,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewWithHost(h host.Host) (c Client, err error) {
|
||||
return Client{
|
||||
h: h,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
h host.Host
|
||||
}
|
||||
|
||||
func (c Client) Register(ctx context.Context, srv ma.Multiaddr, topic string, record enr.Record, ttl time.Duration) error {
|
||||
s, err := c.newStream(ctx, srv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
if err = rlp.Encode(s, protocol.REGISTER); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = rlp.Encode(s, protocol.Register{Topic: topic, Record: record, TTL: uint64(ttl)}); err != nil {
|
||||
return err
|
||||
}
|
||||
rs := rlp.NewStream(s, 0)
|
||||
typ, err := rs.Uint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if protocol.MessageType(typ) != protocol.REGISTER_RESPONSE {
|
||||
return fmt.Errorf("expected %v as response, but got %v", protocol.REGISTER_RESPONSE, typ)
|
||||
}
|
||||
var val protocol.RegisterResponse
|
||||
if err = rs.Decode(&val); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debug("received response to register", "status", val.Status, "message", val.Message)
|
||||
if val.Status != protocol.OK {
|
||||
return fmt.Errorf("register failed. status code %v", val.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Client) Discover(ctx context.Context, srv ma.Multiaddr, topic string, limit int) (rst []enr.Record, err error) {
|
||||
s, err := c.newStream(ctx, srv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
if err = rlp.Encode(s, protocol.DISCOVER); err != nil {
|
||||
return
|
||||
}
|
||||
if err = rlp.Encode(s, protocol.Discover{Topic: topic, Limit: uint(limit)}); err != nil {
|
||||
return
|
||||
}
|
||||
rs := rlp.NewStream(s, 0)
|
||||
typ, err := rs.Uint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if protocol.MessageType(typ) != protocol.DISCOVER_RESPONSE {
|
||||
return nil, fmt.Errorf("expected %v as response, but got %v", protocol.REGISTER_RESPONSE, typ)
|
||||
}
|
||||
var val protocol.DiscoverResponse
|
||||
if err = rs.Decode(&val); err != nil {
|
||||
return
|
||||
}
|
||||
if val.Status != protocol.OK {
|
||||
return nil, fmt.Errorf("discover request failed. status code %v", val.Status)
|
||||
}
|
||||
logger.Debug("received response to discover request", "status", val.Status, "records lth", len(val.Records))
|
||||
return val.Records, nil
|
||||
}
|
||||
|
||||
func (c Client) RemoteIp(ctx context.Context, srv ma.Multiaddr) (value string, err error) {
|
||||
s, err := c.newStream(ctx, srv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
if err = rlp.Encode(s, protocol.REMOTEIP); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rs := rlp.NewStream(s, 0)
|
||||
typ, err := rs.Uint()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if protocol.MessageType(typ) != protocol.REMOTEIP_RESPONSE {
|
||||
err = fmt.Errorf("expected %v as response, but got %v", protocol.REMOTEIP_RESPONSE, typ)
|
||||
return
|
||||
}
|
||||
var val protocol.RemoteIpResponse
|
||||
if err = rs.Decode(&val); err != nil {
|
||||
return
|
||||
}
|
||||
if val.Status != protocol.OK {
|
||||
err = fmt.Errorf("remoteip request failed. status code %v", val.Status)
|
||||
return
|
||||
}
|
||||
logger.Debug("received response to remoteip request", "status", val.Status, "ip", val.IP)
|
||||
value = val.IP
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) newStream(ctx context.Context, srv ma.Multiaddr) (rw network.Stream, err error) {
|
||||
pid, err := srv.ValueForProtocol(ethv4.P_ETHv4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
peerid, err := peer.Decode(pid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// TODO there must be a better interface
|
||||
targetPeerAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ethv4/%s", pid))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
targetAddr := srv.Decapsulate(targetPeerAddr)
|
||||
c.h.Peerstore().AddAddr(peerid, targetAddr, 5*time.Second)
|
||||
s, err := c.h.NewStream(ctx, peerid, "/rend/0.1.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &InstrumentedStream{s}, nil
|
||||
}
|
||||
|
||||
// Close shutdowns the host and all open connections.
|
||||
func (c Client) Close() error {
|
||||
return c.h.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user