1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-07-15 07:58:15 +08:00
Files
kubo/core/commands/p2p.go
Steven Allen fe8846fcd7 gx: mass update
License: MIT
Signed-off-by: Steven Allen <steven@stebalien.com>
2018-01-24 15:58:44 -08:00

413 lines
9.5 KiB
Go

package commands
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"text/tabwriter"
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
ma "gx/ipfs/QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb/go-multiaddr"
"gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
)
// P2PListenerInfoOutput is output type of ls command
type P2PListenerInfoOutput struct {
Protocol string
Address string
}
// P2PStreamInfoOutput is output type of streams command
type P2PStreamInfoOutput struct {
HandlerID string
Protocol string
LocalPeer string
LocalAddress string
RemotePeer string
RemoteAddress string
}
// P2PLsOutput is output type of ls command
type P2PLsOutput struct {
Listeners []P2PListenerInfoOutput
}
// P2PStreamsOutput is output type of streams command
type P2PStreamsOutput struct {
Streams []P2PStreamInfoOutput
}
// P2PCmd is the 'ipfs p2p' command
var P2PCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Libp2p stream mounting.",
ShortDescription: `
Create and use tunnels to remote peers over libp2p
Note: this command is experimental and subject to change as usecases and APIs
are refined`,
},
Subcommands: map[string]*cmds.Command{
"listener": p2pListenerCmd,
"stream": p2pStreamCmd,
},
}
// p2pListenerCmd is the 'ipfs p2p listener' command
var p2pListenerCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "P2P listener management.",
ShortDescription: "Create and manage listener p2p endpoints",
},
Subcommands: map[string]*cmds.Command{
"ls": p2pListenerLsCmd,
"open": p2pListenerListenCmd,
"close": p2pListenerCloseCmd,
},
}
// p2pStreamCmd is the 'ipfs p2p stream' command
var p2pStreamCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "P2P stream management.",
ShortDescription: "Create and manage p2p streams",
},
Subcommands: map[string]*cmds.Command{
"ls": p2pStreamLsCmd,
"dial": p2pStreamDialCmd,
"close": p2pStreamCloseCmd,
},
}
var p2pListenerLsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List active p2p listeners.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("headers", "v", "Print table headers (HandlerID, Protocol, Local, Remote)."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
output := &P2PLsOutput{}
for _, listener := range n.P2P.Listeners.Listeners {
output.Listeners = append(output.Listeners, P2PListenerInfoOutput{
Protocol: listener.Protocol,
Address: listener.Address.String(),
})
}
res.SetOutput(output)
},
Type: P2PLsOutput{},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
headers, _, _ := res.Request().Option("headers").Bool()
list := v.(*P2PLsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
for _, listener := range list.Listeners {
if headers {
fmt.Fprintln(w, "Address\tProtocol")
}
fmt.Fprintf(w, "%s\t%s\n", listener.Address, listener.Protocol)
}
w.Flush()
return buf, nil
},
},
}
var p2pStreamLsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List active p2p streams.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote)."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
output := &P2PStreamsOutput{}
for _, s := range n.P2P.Streams.Streams {
output.Streams = append(output.Streams, P2PStreamInfoOutput{
HandlerID: strconv.FormatUint(s.HandlerID, 10),
Protocol: s.Protocol,
LocalPeer: s.LocalPeer.Pretty(),
LocalAddress: s.LocalAddr.String(),
RemotePeer: s.RemotePeer.Pretty(),
RemoteAddress: s.RemoteAddr.String(),
})
}
res.SetOutput(output)
},
Type: P2PStreamsOutput{},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
headers, _, _ := res.Request().Option("headers").Bool()
list := v.(*P2PStreamsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
for _, stream := range list.Streams {
if headers {
fmt.Fprintln(w, "HandlerID\tProtocol\tLocal\tRemote")
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", stream.HandlerID, stream.Protocol, stream.LocalAddress, stream.RemotePeer)
}
w.Flush()
return buf, nil
},
},
}
var p2pListenerListenCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Forward p2p connections to a network multiaddr.",
ShortDescription: `
Register a p2p connection handler and forward the connections to a specified
address.
Note that the connections originate from the ipfs daemon process.
`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("Protocol", true, false, "Protocol identifier."),
cmdkit.StringArg("Address", true, false, "Request handling application address."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
proto := "/p2p/" + req.Arguments()[0]
if n.P2P.CheckProtoExists(proto) {
res.SetError(errors.New("protocol handler already registered"), cmdkit.ErrNormal)
return
}
addr, err := ma.NewMultiaddr(req.Arguments()[1])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
_, err = n.P2P.NewListener(n.Context(), proto, addr)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
// Successful response.
res.SetOutput(&P2PListenerInfoOutput{
Protocol: proto,
Address: addr.String(),
})
},
}
var p2pStreamDialCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Dial to a p2p listener.",
ShortDescription: `
Establish a new connection to a peer service.
When a connection is made to a peer service the ipfs daemon will setup one
time TCP listener and return it's bind port, this way a dialing application
can transparently connect to a p2p service.
`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("Peer", true, false, "Remote peer to connect to"),
cmdkit.StringArg("Protocol", true, false, "Protocol identifier."),
cmdkit.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
addr, peer, err := ParsePeerParam(req.Arguments()[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
proto := "/p2p/" + req.Arguments()[1]
bindAddr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
if len(req.Arguments()) == 3 {
bindAddr, err = ma.NewMultiaddr(req.Arguments()[2])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
}
listenerInfo, err := n.P2P.Dial(n.Context(), addr, peer, proto, bindAddr)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
output := P2PListenerInfoOutput{
Protocol: listenerInfo.Protocol,
Address: listenerInfo.Address.String(),
}
res.SetOutput(&output)
},
}
var p2pListenerCloseCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Close active p2p listener.",
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("Protocol", false, false, "P2P listener protocol"),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("all", "a", "Close all listeners."),
},
Run: func(req cmds.Request, res cmds.Response) {
res.SetOutput(nil)
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
closeAll, _, _ := req.Option("all").Bool()
var proto string
if !closeAll {
if len(req.Arguments()) == 0 {
res.SetError(errors.New("no protocol name specified"), cmdkit.ErrNormal)
return
}
proto = "/p2p/" + req.Arguments()[0]
}
for _, listener := range n.P2P.Listeners.Listeners {
if !closeAll && listener.Protocol != proto {
continue
}
listener.Close()
if !closeAll {
break
}
}
},
}
var p2pStreamCloseCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Close active p2p stream.",
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("HandlerID", false, false, "Stream HandlerID"),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("all", "a", "Close all streams."),
},
Run: func(req cmds.Request, res cmds.Response) {
res.SetOutput(nil)
n, err := getNode(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
closeAll, _, _ := req.Option("all").Bool()
var handlerID uint64
if !closeAll {
if len(req.Arguments()) == 0 {
res.SetError(errors.New("no HandlerID specified"), cmdkit.ErrNormal)
return
}
handlerID, err = strconv.ParseUint(req.Arguments()[0], 10, 64)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
}
for _, stream := range n.P2P.Streams.Streams {
if !closeAll && handlerID != stream.HandlerID {
continue
}
stream.Close()
if !closeAll {
break
}
}
},
}
func getNode(req cmds.Request) (*core.IpfsNode, error) {
n, err := req.InvocContext().GetNode()
if err != nil {
return nil, err
}
config, err := n.Repo.Config()
if err != nil {
return nil, err
}
if !config.Experimental.Libp2pStreamMounting {
return nil, errors.New("libp2p stream mounting not enabled")
}
if !n.OnlineMode() {
return nil, errNotOnline
}
return n, nil
}