Skip to content

Commit

Permalink
Merge pull request #34 from filecoin-project/feat/networking
Browse files Browse the repository at this point in the history
Add in basic libp2p host, and commands for establishing connectivity
  • Loading branch information
whyrusleeping authored Feb 5, 2018
2 parents 1f5c7eb + 67c5228 commit 08bfead
Show file tree
Hide file tree
Showing 11 changed files with 516 additions and 36 deletions.
2 changes: 1 addition & 1 deletion commands/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
"io"

cmds "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds"
cmds "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"

"github.com/filecoin-project/go-filecoin/types"
Expand Down
45 changes: 39 additions & 6 deletions commands/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"net/http"
"os"
"os/signal"
"time"

cmds "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds"
cmdhttp "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds/http"
libp2p "gx/ipfs/QmT68EgyFbnSs5rbHkNkFZQwjdHfqrJiGr3R6rwcwnzYLc/go-libp2p"
cmds "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds"
cmdhttp "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds/http"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"

"github.com/filecoin-project/go-filecoin/node"
Expand All @@ -18,20 +20,38 @@ var daemonCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "start the filecoin daemon",
},
Options: []cmdkit.Option{
cmdkit.StringOption("swarmlisten").WithDefault("/ip4/127.0.0.1/tcp/6000"),
},
Run: daemonRun,
}

func daemonRun(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) {
api := req.Options[OptionAPI].(string)

node := node.New()
if err := startNode(node, api); err != nil {
// TODO: this should be passed in from a config file, not an api flag
libp2pOpts := node.Libp2pOptions(
libp2p.ListenAddrStrings(req.Options["swarmlisten"].(string)),
)

fcn, err := node.New(req.Context, libp2pOpts)
if err != nil {
re.SetError(err, cmdkit.ErrNormal)
return
}

fmt.Println("My peer ID is", fcn.Host.ID().Pretty())
for _, a := range fcn.Host.Addrs() {
fmt.Println("Swarm listening on", a)
}

if err := runAPIAndWait(req.Context, fcn, api); err != nil {
re.SetError(err, cmdkit.ErrNormal)
return
}
}

func startNode(node *node.Node, api string) error {
func runAPIAndWait(ctx context.Context, node *node.Node, api string) error {
if err := node.Start(); err != nil {
return err
}
Expand All @@ -50,13 +70,26 @@ func startNode(node *node.Node, api string) error {
signal.Notify(sigc, os.Interrupt)
defer signal.Stop(sigc)

apiserv := http.Server{
Addr: api,
Handler: handler,
}

go func() {
panic(http.ListenAndServe(api, handler))
}()

<-sigc
fmt.Println("Got interrupt, shutting down...")
go node.Stop()

// allow 5 seconds for clean shutdown. Ideally it would never take this long.
ctx, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()

if err := apiserv.Shutdown(ctx); err != nil {
fmt.Println("failed to shut down api server:", err)
}
node.Stop()

return nil
}
2 changes: 1 addition & 1 deletion commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package commands
import (
"context"

cmds "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds"
cmds "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds"

"github.com/filecoin-project/go-filecoin/node"
)
Expand Down
77 changes: 77 additions & 0 deletions commands/id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package commands

import (
"encoding/json"
"fmt"
"io"
"strings"

cmds "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"

"github.com/filecoin-project/go-filecoin/node"
)

// idOutput is the output of the /id api endpoint
type idOutput struct {
Addresses []string
ID string
AgentVersion string
ProtocolVersion string
PublicKey string
}

func idOutputFromNode(fcn *node.Node) *idOutput {
var out idOutput
for _, a := range fcn.Host.Addrs() {
out.Addresses = append(out.Addresses, fmt.Sprintf("%s/ipfs/%s", a, fcn.Host.ID().Pretty()))
}
out.ID = fcn.Host.ID().Pretty()
return &out
}

var idCmd = &cmds.Command{
Options: []cmdkit.Option{
// TODO: ideally copy this from the `ipfs id` command
cmdkit.StringOption("format", "f", "specify an output format"),
},
Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) {
fcn := GetNode(env)

out := idOutputFromNode(fcn)

re.Emit(out)
},
Type: idOutput{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, val *idOutput) error {
format, found := req.Options["format"].(string)
if found {
output := idFormatSubstitute(format, val)
_, err := fmt.Fprint(w, output)
return err
}

marshaled, err := json.MarshalIndent(val, "", "\t")
if err != nil {
return err
}
marshaled = append(marshaled, byte('\n'))

_, err = w.Write(marshaled)
return err
}),
},
}

func idFormatSubstitute(format string, val *idOutput) string {
output := format
output = strings.Replace(output, "<id>", val.ID, -1)
output = strings.Replace(output, "<aver>", val.AgentVersion, -1)
output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1)
output = strings.Replace(output, "<pubkey>", val.PublicKey, -1)
output = strings.Replace(output, "<addrs>", strings.Join(val.Addresses, "\n"), -1)
output = strings.Replace(output, "\\n", "\n", -1)
output = strings.Replace(output, "\\t", "\t", -1)
return output
}
39 changes: 19 additions & 20 deletions commands/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"net"
"os"

cmds "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds"
cmdcli "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds/cli"
cmdhttp "gx/ipfs/Qmc5paX4ECBARnAKkcAmUYHBGor228Tkfxeya3Nu2KRL46/go-ipfs-cmds/http"
cmds "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds"
cmdcli "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds/cli"
cmdhttp "gx/ipfs/QmWGgKRz5S24SqaAapF5PPCfYfLT7MexJZewN5M82CQTzs/go-ipfs-cmds/http"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
)

Expand All @@ -26,33 +26,37 @@ var (
ErrMissingDaemon = errors.New("daemon must be started before using this command")
)

func defaultAPIAddr() string {
// Until we have a config file, we need an easy way to influence the API
// address for testing
if envapi := os.Getenv("FIL_API"); envapi != "" {
return envapi
}

return ":3453"
}

var rootCmd = &cmds.Command{
Options: []cmdkit.Option{
cmdkit.StringOption(OptionAPI, "set the api port to use").WithDefault(":3453"),
cmdkit.StringOption(OptionAPI, "set the api port to use").WithDefault(defaultAPIAddr()),
cmds.OptionEncodingType,
},
Subcommands: make(map[string]*cmds.Command),
}

// All commands that require the daemon to be running
// all top level commands. set during init() to avoid configuration loops.
var rootSubcmdsDaemon = map[string]*cmds.Command{
"chain": chainCmd,
}

// All commands that require the daemon _not_ to be running
var rootSubcmdsNoDaemon = map[string]*cmds.Command{
"chain": chainCmd,
"daemon": daemonCmd,
"id": idCmd,
"swarm": SwarmCmd,
"version": versionCmd,
}

func init() {
for k, v := range rootSubcmdsDaemon {
rootCmd.Subcommands[k] = v
}

for k, v := range rootSubcmdsNoDaemon {
rootCmd.Subcommands[k] = v
}
}

// Run processes the arguments and stdin
Expand Down Expand Up @@ -84,12 +88,7 @@ func Run(args []string, stdin *os.File) (int, error) {
}

func requiresDaemon(req *cmds.Request) bool {
for _, v := range rootSubcmdsDaemon {
if req.Command == v {
return true
}
}
return false
return req.Command != daemonCmd
}

func dispatchRemoteCmd(req *cmds.Request, api string) (int, error) {
Expand Down
Loading

0 comments on commit 08bfead

Please sign in to comment.