Skip to content

Commit

Permalink
feat(cmd.Config): re-add support for configuration files
Browse files Browse the repository at this point in the history
thanks to gateway nodes dying, we need a way to modify our bootstrap list.
To do this the right way, I've brought back config.json, this time stored
in $QRI_PATH.
We've also added a new command "boostrap" that allows listing, adding,
and removing bootstrap addresses.

closes #108
  • Loading branch information
b5 committed Nov 9, 2017
1 parent 60bce71 commit 6305d22
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 98 deletions.
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ FROM golang:1.9
LABEL maintainer="sparkle_pony_2000@qri.io"

ADD . /go/src/github.com/qri-io/qri
RUN cd /go/src/github.com/qri-io/qri

RUN go get -u github.com/whyrusleeping/gx
# RUN go get -u github.com/whyrusleeping/gx
# RUN go get -u github.com/whyrusleeping/gx-go
RUN cd /go/src/github.com/qri-io/qri && gx install

RUN go get ./...
# RUN gx install
# RUN go get ./...

RUN go install github.com/qri-io/qri
# set default port to 8080, default log level, QRI_PATH env, IPFS_PATH env
Expand Down
2 changes: 2 additions & 0 deletions api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ type Config struct {
MemOnly bool
// disable networking
Online bool
// list of addresses to bootsrap qri peers on
BoostrapAddrs []string
}

// Validate returns nil if this configuration is valid,
Expand Down
3 changes: 3 additions & 0 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ func New(options ...func(*Config)) (s *Server, err error) {
ncfg.Repo = qrepo
ncfg.RepoPath = s.cfg.QriRepoPath
ncfg.Online = s.cfg.Online
if cfg.BoostrapAddrs != nil {
ncfg.QriBootstrapAddrs = cfg.BoostrapAddrs
}
})
if err != nil {
return s, err
Expand Down
63 changes: 63 additions & 0 deletions cmd/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package cmd

import (
"github.com/qri-io/qri/p2p"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// bootstrapCmd represents the bootstrap command
var bootstrapCmd = &cobra.Command{
Use: "bootstrap",
Aliases: []string{"bs"},
Short: "show or edit the list of qri bootstrap peers",
}

var bootstrapListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "Show a configuration setting",
Run: func(cmd *cobra.Command, args []string) {
list := viper.GetStringSlice("bootstrap")
for _, i := range list {
PrintInfo("%s\n", i)
}
},
}

var boostrapAddCmd = &cobra.Command{
Use: "add",
Short: "add peers to the bootstrap list",
Run: func(cmd *cobra.Command, args []string) {
_, err := p2p.ParseMultiaddrs(args)
ExitIfErr(err)
addrs := append(viper.GetStringSlice("bootstrap"), args...)
// TODO - fix!!!
WriteConfigFile(&Config{Bootstrap: addrs})
},
}

var boostrapRmCmd = &cobra.Command{
Use: "remove",
Aliases: []string{"rm"},
Short: "remove peers from the bootstrap list",
Run: func(cmd *cobra.Command, args []string) {
addrs := viper.GetStringSlice("bootstrap")
for _, rm := range args {
for i, adr := range addrs {
if rm == adr {
addrs = append(addrs[:i], addrs[i+1:]...)
}
}
}
// TODO - fix!!!
WriteConfigFile(&Config{Bootstrap: addrs})
},
}

func init() {
bootstrapCmd.AddCommand(bootstrapListCmd)
bootstrapCmd.AddCommand(boostrapAddCmd)
bootstrapCmd.AddCommand(boostrapRmCmd)
RootCmd.AddCommand(bootstrapCmd)
}
72 changes: 68 additions & 4 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/qri-io/qri/p2p"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type Config struct {
Bootstrap []string
Bootstrap []string `json:"bootstrap"`
}

var defaultCfg = &Config{
Bootstrap: p2p.DefaultBootstrapAddresses,
}

// configCmd represents the config command
Expand Down Expand Up @@ -42,11 +50,67 @@ func init() {
RootCmd.AddCommand(configCmd)
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
home := userHomeDir()
SetNoColor()

// if cfgFile is specified, override
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
err := viper.ReadInConfig()
ExitIfErr(err)
return
}

qriPath := os.Getenv("QRI_PATH")
if qriPath == "" {
qriPath = filepath.Join(home, ".qri")
}
// TODO - this is stupid
qriPath = strings.Replace(qriPath, "~", home, 1)
viper.SetDefault(QriRepoPath, filepath.Join(qriPath))
if err := os.MkdirAll(qriPath, os.ModePerm); err != nil {
fmt.Errorf("error creating home dir: %s\n", err.Error())
}

ipfsFsPath := os.Getenv("IPFS_PATH")
if ipfsFsPath == "" {
ipfsFsPath = "$HOME/.ipfs"
}
ipfsFsPath = strings.Replace(ipfsFsPath, "~", home, 1)
viper.SetDefault(IpfsFsPath, ipfsFsPath)

viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath(qriPath) // add QRI_PATH env var

err := EnsureConfigFile()
ExitIfErr(err)

err = viper.ReadInConfig()
ExitIfErr(err)
}

func configFilepath() string {
path := viper.ConfigFileUsed()
if path == "" {
path = filepath.Join(viper.GetString(QriRepoPath), "config.json")
}
return path
}

func EnsureConfigFile() error {
if _, err := os.Stat(configFilepath()); os.IsNotExist(err) {
fmt.Println("writing config file")
return WriteConfigFile(defaultCfg)
}
return nil
}

func WriteConfigFile(cfg *Config) error {
data, err := json.MarshalIndent(cfg, "", "\t")
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}

return ioutil.WriteFile(fmt.Sprintf("%s/.qri.json", os.Getenv("HOME")), data, os.ModePerm)
return ioutil.WriteFile(configFilepath(), data, os.ModePerm)
}
33 changes: 0 additions & 33 deletions cmd/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,3 @@ func GetIpfsFilestore(online bool) *ipfs.Filestore {
ExitIfErr(err)
return fs
}

// func FindDataset(r repo.Repo, store cafs.Filestore, arg string) (*dataset.Dataset, error) {
// path, err := r.GetPath(arg)
// if err == nil {
// return dsfs.LoadDataset(store, path)
// }
// // TODO - add lookups by hashes & stuff
// return nil, cafs.ErrNotFound
// }

// func DatasetRef(r repo.Repo, store cafs.Filestore, arg string) (*repo.DatasetRef, error) {
// path, err := r.GetPath(arg)
// if err != nil {
// return nil, err
// }

// ds, err := dsfs.LoadDataset(store, path)
// if err != nil {
// return nil, err
// }
// // TODO - add hash lookup

// name, err := r.GetName(path)
// if err != nil {
// return nil, err
// }

// return &repo.DatasetRef{
// Path: path,
// Name: name,
// Dataset: ds,
// }, nil
// }
47 changes: 0 additions & 47 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ package cmd

import (
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var cfgFile string
Expand Down Expand Up @@ -42,47 +39,3 @@ func init() {
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $QRI_PATH/config.json)")
RootCmd.PersistentFlags().BoolVarP(&noColor, "no-color", "c", false, "disable colorized output")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
home := userHomeDir()
SetNoColor()

// if cfgFile is specified, override
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
err := viper.ReadInConfig()
ExitIfErr(err)
return
}

// if err := os.Mkdir(filepath.Join(userHomeDir(), ".qri"), os.ModePerm); err != nil {
// fmt.Errorf("error creating home dir: %s\n", err.Error())
// }
qriPath := os.Getenv("QRI_PATH")
if qriPath == "" {
qriPath = filepath.Join(home, "qri")
}

viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath(qriPath) // add QRI_PATH env var
// viper.AddConfigPath("$HOME/.qri/config") // adding home directory as first search path
// viper.AddConfigPath(".") // adding home directory as first search path
viper.AutomaticEnv() // read in environment variables that match

// TODO - this is stupid
qriPath = strings.Replace(qriPath, "~", home, 1)
viper.SetDefault(QriRepoPath, qriPath)

ipfsFsPath := os.Getenv("IPFS_PATH")
if ipfsFsPath == "" {
ipfsFsPath = "$HOME/.ipfs"
}
ipfsFsPath = strings.Replace(ipfsFsPath, "~", home, 1)
viper.SetDefault(IpfsFsPath, ipfsFsPath)

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
// fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
1 change: 1 addition & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var serverCmd = &cobra.Command{
cfg.QriRepoPath = viper.GetString(QriRepoPath)
cfg.FsStorePath = viper.GetString(IpfsFsPath)
cfg.Online = !serverOffline
cfg.BoostrapAddrs = viper.GetStringSlice("bootstrap")
})
ExitIfErr(err)

Expand Down
2 changes: 1 addition & 1 deletion p2p/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// One day it would be super nice to bootstrap from a stored history & only
// use these for first-round bootstrapping.
var DefaultBootstrapAddresses = []string{
"/ip4/35.192.124.143/tcp/4001/ipfs/QmXhrdvGRBF5ocvgdLdnMDBMbxJWDngZDBjS2PUYc4ahpb",
"/ip4/35.192.124.143/tcp/4001/ipfs/QmQffqhgce94UFS9mSvvqcAWXQNr1bcZRM659VFakySair",
}

// Bootstrap samples a subset of peers & requests their peers list
Expand Down
8 changes: 6 additions & 2 deletions p2p/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ type NodeCfg struct {
// default port to bind tcp listener to
// ignored if Addrs is supplied
Port int
// list of addresses to bootstrap qri node from
QriBootstrapAddrs []string
// List of multiaddresses to listen on
Addrs []ma.Multiaddr
// secure connection flag. if true
// PubKey & PrivKey are required
// PubKey & PrivKey are required. just, like, never set this
// to false, okay?
Secure bool
}

Expand Down Expand Up @@ -65,7 +68,8 @@ func DefaultNodeCfg() *NodeCfg {
// TODO - enabling this causes all nodes to broadcast
// on the same address, which isn't good. figure out why
// Port: 4444,
Secure: true,
QriBootstrapAddrs: DefaultBootstrapAddresses,
Secure: true,
}
}

Expand Down
2 changes: 1 addition & 1 deletion p2p/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (n *QriNode) StartDiscovery() error {
// Check our existing peerstore for any potential friends
go n.DiscoverPeerstoreQriPeers(n.Host.Peerstore())
// Boostrap off of default addresses
go n.Bootstrap(DefaultBootstrapAddresses)
go n.Bootstrap(n.BootstrapAddrs)

return nil
}
Expand Down
15 changes: 9 additions & 6 deletions p2p/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type QriNode struct {

Repo repo.Repo // repository of this node's qri data
Store cafs.Filestore // a content addressed filestore for data storage, usually ipfs

BootstrapAddrs []string // list of addresses to bootrap *qri* from (not IPFS)
}

// NewQriNode creates a new node, providing no arguments will use
Expand All @@ -56,12 +58,13 @@ func NewQriNode(store cafs.Filestore, options ...func(o *NodeCfg)) (*QriNode, er
ps := pstore.NewPeerstore()

node := &QriNode{
log: cfg.Logger,
Identity: cfg.PeerId,
Online: cfg.Online,
QriPeers: ps,
Repo: cfg.Repo,
Store: store,
log: cfg.Logger,
Identity: cfg.PeerId,
Online: cfg.Online,
QriPeers: ps,
Repo: cfg.Repo,
Store: store,
BootstrapAddrs: cfg.QriBootstrapAddrs,
}

if cfg.Online {
Expand Down

0 comments on commit 6305d22

Please sign in to comment.