-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from filecoin-project/feat/netcli
Network CLI
- Loading branch information
Showing
15 changed files
with
383 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package api | ||
|
||
import ( | ||
"encoding/json" | ||
ma "github.com/multiformats/go-multiaddr" | ||
) | ||
|
||
// TODO: check if this exists anywhere else | ||
type MultiaddrSlice []ma.Multiaddr | ||
|
||
func (m *MultiaddrSlice) UnmarshalJSON(raw []byte) (err error) { | ||
var temp []string | ||
if err := json.Unmarshal(raw, &temp); err != nil { | ||
return err | ||
} | ||
|
||
res := make([]ma.Multiaddr, len(temp)) | ||
for i, str := range temp { | ||
res[i], err = ma.NewMultiaddr(str) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
*m = res | ||
return nil | ||
} | ||
|
||
var _ json.Unmarshaler = new(MultiaddrSlice) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,48 @@ | ||
package cli | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
|
||
"github.com/filecoin-project/go-lotus/api" | ||
"gopkg.in/urfave/cli.v2" | ||
) | ||
|
||
// Commands is the root group of CLI commands | ||
const ( | ||
metadataContext = "context" | ||
metadataAPI = "api" | ||
) | ||
|
||
// ApiConnector returns API instance | ||
type ApiConnector func() api.API | ||
|
||
func getApi(ctx *cli.Context) api.API { | ||
return ctx.App.Metadata[metadataAPI].(ApiConnector)() | ||
} | ||
|
||
// reqContext returns context for cli execution. Calling it for the first time | ||
// installs SIGTERM handler that will close returned context. | ||
// Not safe for concurrent execution. | ||
func reqContext(cctx *cli.Context) context.Context { | ||
if uctx, ok := cctx.App.Metadata[metadataContext]; ok { | ||
// unchecked cast as if something else is in there | ||
// it is crash worthy either way | ||
return uctx.(context.Context) | ||
} | ||
ctx, done := context.WithCancel(context.Background()) | ||
sigChan := make(chan os.Signal, 2) | ||
go func() { | ||
<-sigChan | ||
done() | ||
}() | ||
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) | ||
|
||
return ctx | ||
} | ||
|
||
var Commands = []*cli.Command{ | ||
netCmd, | ||
versionCmd, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
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, | ||
netListen, | ||
}, | ||
} | ||
|
||
var netPeers = &cli.Command{ | ||
Name: "peers", | ||
Usage: "Print peers", | ||
Action: func(cctx *cli.Context) error { | ||
api := getApi(cctx) | ||
ctx := reqContext(cctx) | ||
peers, err := api.NetPeers(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, peer := range peers { | ||
fmt.Println(peer) | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
var netListen = &cli.Command{ | ||
Name: "listen", | ||
Usage: "List listen addresses", | ||
Action: func(cctx *cli.Context) error { | ||
api := getApi(cctx) | ||
ctx := reqContext(cctx) | ||
|
||
addrs, err := api.NetAddrsListen(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, peer := range addrs { | ||
fmt.Println(peer) | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
var netConnect = &cli.Command{ | ||
Name: "connect", | ||
Usage: "Connect to a peer", | ||
Action: func(cctx *cli.Context) error { | ||
api := getApi(cctx) | ||
ctx := reqContext(cctx) | ||
|
||
pis, err := parseAddresses(ctx, cctx.Args().Slice()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, pi := range pis { | ||
fmt.Printf("connect %s: ", pi.ID.Pretty()) | ||
err := api.NetConnect(ctx, 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// +build nodaemon | ||
|
||
package daemon | ||
|
||
import ( | ||
"errors" | ||
|
||
"gopkg.in/urfave/cli.v2" | ||
) | ||
|
||
// Cmd is the `go-lotus daemon` command | ||
var Cmd = &cli.Command{ | ||
Name: "daemon", | ||
Usage: "Start a lotus daemon process", | ||
Flags: []cli.Flag{ | ||
&cli.StringFlag{ | ||
Name: "api", | ||
Value: ":1234", | ||
}, | ||
}, | ||
Action: func(cctx *cli.Context) error { | ||
return errors.New("daemon support not included in this binary") | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.