-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Network CLI #9
Network CLI #9
Changes from 2 commits
cdca2ff
f9b5343
9a244eb
797ef4e
8289016
d852b3f
40d9fbd
66a67b0
980bed1
f9a34b3
093fabc
1bead4b
7069d57
63b316b
5b04fbb
271c268
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,18 @@ | ||
package cli | ||
|
||
import ( | ||
"github.com/filecoin-project/go-lotus/api" | ||
"gopkg.in/urfave/cli.v2" | ||
) | ||
|
||
type ApiConnector func() api.API | ||
|
||
func getApi(ctx *cli.Context) api.API { | ||
return ctx.App.Metadata["api"].(ApiConnector)() | ||
} | ||
|
||
// Commands is the root group of CLI commands | ||
var Commands = []*cli.Command{ | ||
netCmd, | ||
versionCmd, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package cli | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sync" | ||
"time" | ||
|
||
"github.com/libp2p/go-libp2p-core/peer" | ||
ma "github.com/multiformats/go-multiaddr" | ||
madns "github.com/multiformats/go-multiaddr-dns" | ||
"gopkg.in/urfave/cli.v2" | ||
) | ||
|
||
var netCmd = &cli.Command{ | ||
Name: "net", | ||
Usage: "Manage P2P Network", | ||
Subcommands: []*cli.Command{ | ||
netPeers, | ||
netConnect, | ||
}, | ||
} | ||
|
||
var netPeers = &cli.Command{ | ||
Name: "peers", | ||
Usage: "Print peers", | ||
Action: func(ctx *cli.Context) error { | ||
api := getApi(ctx) | ||
fmt.Println(api.NetPeers(context.Background())) | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
var netConnect = &cli.Command{ | ||
Name: "connect", | ||
Usage: "Connect to a peer", | ||
Action: func(ctx *cli.Context) error { | ||
pis, err := parseAddresses(context.Background(), ctx.Args().Slice()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
api := getApi(ctx) | ||
for _, pi := range pis { | ||
fmt.Printf("connect %s", pi.ID.Pretty()) | ||
err := api.NetConnect(context.Background(), pi) | ||
if err != nil { | ||
fmt.Println("failure") | ||
return err | ||
} | ||
fmt.Println("success") | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
// parseAddresses is a function that takes in a slice of string peer addresses | ||
// (multiaddr + peerid) and returns a slice of properly constructed peers | ||
func parseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) { | ||
// resolve addresses | ||
maddrs, err := resolveAddresses(ctx, addrs) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return peer.AddrInfosFromP2pAddrs(maddrs...) | ||
} | ||
|
||
const ( | ||
dnsResolveTimeout = 10 * time.Second | ||
) | ||
|
||
// resolveAddresses resolves addresses parallelly | ||
func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, error) { | ||
ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout) | ||
defer cancel() | ||
|
||
var maddrs []ma.Multiaddr | ||
var wg sync.WaitGroup | ||
resolveErrC := make(chan error, len(addrs)) | ||
|
||
maddrC := make(chan ma.Multiaddr) | ||
|
||
for _, addr := range addrs { | ||
maddr, err := ma.NewMultiaddr(addr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// check whether address ends in `ipfs/Qm...` | ||
if _, last := ma.SplitLast(maddr); last.Protocol().Code == ma.P_IPFS { | ||
maddrs = append(maddrs, maddr) | ||
continue | ||
} | ||
wg.Add(1) | ||
go func(maddr ma.Multiaddr) { | ||
defer wg.Done() | ||
raddrs, err := madns.Resolve(ctx, maddr) | ||
if err != nil { | ||
resolveErrC <- err | ||
return | ||
} | ||
// filter out addresses that still doesn't end in `ipfs/Qm...` | ||
found := 0 | ||
for _, raddr := range raddrs { | ||
if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS { | ||
maddrC <- raddr | ||
found++ | ||
} | ||
} | ||
if found == 0 { | ||
resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr) | ||
} | ||
}(maddr) | ||
} | ||
go func() { | ||
wg.Wait() | ||
close(maddrC) | ||
}() | ||
|
||
for maddr := range maddrC { | ||
maddrs = append(maddrs, maddr) | ||
} | ||
|
||
select { | ||
case err := <-resolveErrC: | ||
return nil, err | ||
default: | ||
} | ||
|
||
return maddrs, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package node | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"reflect" | ||
|
||
"github.com/filecoin-project/go-lotus/api" | ||
"github.com/filecoin-project/go-lotus/build" | ||
|
||
"github.com/libp2p/go-libp2p-core/host" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
"github.com/multiformats/go-multiaddr" | ||
"go.uber.org/fx" | ||
) | ||
|
||
var errTyp = reflect.TypeOf(new(error)).Elem() | ||
|
||
// TODO: type checking, this isn't JS | ||
func provideApi(f interface{}, toProvide interface{}) fx.Option { | ||
rf := reflect.ValueOf(f) | ||
tp := reflect.ValueOf(toProvide).Elem() | ||
|
||
ins := make([]reflect.Type, rf.Type().NumIn()) | ||
for i := range ins { | ||
ins[i] = rf.Type().In(i) | ||
} | ||
|
||
ctyp := reflect.FuncOf(ins, []reflect.Type{errTyp}, rf.Type().IsVariadic()) | ||
|
||
return fx.Invoke(reflect.MakeFunc(ctyp, func(args []reflect.Value) (results []reflect.Value) { | ||
provided := rf.Call(args) | ||
tp.Set(provided[0].Elem().Convert(tp.Type())) | ||
return []reflect.Value{reflect.ValueOf(new(error)).Elem()} | ||
}).Interface()) | ||
} | ||
|
||
func apiOption(resAPI *api.Struct) fx.Option { | ||
in := &resAPI.Internal | ||
|
||
return fx.Options( | ||
provideApi(versionAPI, &in.Version), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are we building the api stuff with DI? That seems like it shouldnt be that hard to do manually (actually, seems easier to do manually to me) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not against doing this 'manually', just wanted to investigate alternative approaches. The main point of this is avoiding the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, In general, I don't think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Went with go-ipfs (coreapi) / go-filecoin way - d852b3f, changing to something else in the future should be easy enough |
||
provideApi(idAPI, &in.ID), | ||
provideApi(netPeersAPI, &in.NetPeers), | ||
provideApi(netConnectAPI, &in.NetConnect), | ||
) | ||
} | ||
|
||
func idAPI(id peer.ID) interface{} { | ||
return func(ctx context.Context) (peer.ID, error) { | ||
return id, nil | ||
} | ||
} | ||
|
||
func versionAPI() interface{} { | ||
return func(context.Context) (api.Version, error) { | ||
return api.Version{ | ||
Version: build.Version, | ||
}, nil | ||
} | ||
} | ||
|
||
func netPeersAPI(h host.Host) interface{} { | ||
return func(ctx context.Context) ([]peer.AddrInfo, error) { | ||
conns := h.Network().Conns() | ||
out := make([]peer.AddrInfo, len(conns)) | ||
|
||
for i, conn := range conns { | ||
out[i] = peer.AddrInfo{ | ||
ID: conn.RemotePeer(), | ||
Addrs: []multiaddr.Multiaddr{ | ||
conn.RemoteMultiaddr(), | ||
}, | ||
} | ||
} | ||
|
||
return out, nil | ||
} | ||
} | ||
|
||
func netConnectAPI(h host.Host) interface{} { | ||
return func(ctx context.Context, p peer.AddrInfo) error { | ||
return errors.New("nope") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a slightly weird way to wire this through
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed (this is just the first thing I tried)