diff --git a/config/config.go b/config/config.go index f7465e425..a22a1e7c4 100644 --- a/config/config.go +++ b/config/config.go @@ -37,7 +37,7 @@ func (Config) Default() *Config { CLI: DefaultCLI(), API: DefaultAPI(), - P2P: P2P{}.Default(), + P2P: DefaultP2P(), Webapp: Webapp{}.Default(), RPC: RPC{}.Default(), Logging: DefaultLogging(), diff --git a/config/p2p.go b/config/p2p.go index 4b5dfa5a9..2d6acbb49 100644 --- a/config/p2p.go +++ b/config/p2p.go @@ -8,43 +8,45 @@ import ( ma "gx/ipfs/QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb/go-multiaddr" peer "gx/ipfs/QmZoWKhxUmZ2seW4BzX6fJkNR8hh9PsGModr7q171yq2SS/go-libp2p-peer" crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" + + "github.com/qri-io/jsonschema" ) // P2P encapsulates configuration options for qri peer-2-peer communication type P2P struct { // Enabled is a flag for weather this node should connect // to the distributed network - Enabled bool + Enabled bool `json:"enabled"` // PeerID is this nodes peer identifier - PeerID string + PeerID string `json:"peerid"` - PubKey string - PrivKey string + PubKey string `json:"pubkey"` + PrivKey string `json:"privkey"` // Port default port to bind a tcp listener to // ignored if Addrs is supplied - Port int + Port int `json:"port"` // List of multiaddresses to listen on - Addrs []ma.Multiaddr + Addrs []ma.Multiaddr `json:"addrs"` // QriBootstrapAddrs lists addresses to bootstrap qri node from - QriBootstrapAddrs []string + QriBootstrapAddrs []string `json:"qribootstrapaddrs"` // ProfileReplication determines what to do when this peer sees messages // broadcast by it's own profile (from another peer instance). setting // ProfileReplication == "full" will cause this peer to automatically pin // any data that is verifyably posted by the same peer - ProfileReplication string + ProfileReplication string `json:"profilereplication"` // list of addresses to bootsrap qri peers on - BoostrapAddrs []string + BoostrapAddrs []string `json:"bootstrapaddrs"` } -// Default generates sensible settings for p2p, generating a new randomized +// DefaultP2P generates sensible settings for p2p, generating a new randomized // private key & peer id -func (P2P) Default() *P2P { +func DefaultP2P() *P2P { r := rand.Reader p2p := &P2P{ Enabled: true, @@ -96,6 +98,74 @@ func (cfg *P2P) DecodePeerID() (peer.ID, error) { return peer.IDB58Decode(cfg.PeerID) } +// Validate validates all fields of p2p returning all errors found. +func (cfg P2P) Validate() error { + schema := jsonschema.Must(`{ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "P2P", + "description": "Config for the p2p", + "type": "object", + "required": ["enabled", "peerid", "pubkey", "privkey", "port", "addrs", "qribootstrapaddrs", "profilereplication", "bootstrapaddrs"], + "properties": { + "enabled": { + "description": "When true, peer to peer communication is allowed", + "type": "boolean" + }, + "peerid": { + "description": "The peerid is this nodes peer identifier", + "type": "string" + }, + "pubkey": { + "description": "", + "type": "string" + }, + "privkey": { + "description": "", + "type": "string" + }, + "port": { + "description": "Port to bind a tcp lister to. Field is ignored if addrs is supplied", + "type": "integer" + }, + "addrs": { + "description": "List of multiaddresses to listen on", + "anyOf": [ + {"type": "array"}, + {"type": "null"} + ], + "items": { + "type": "string" + } + }, + "qribootstrapaddrs": { + "description": "List of addresses to bootstrap the qri node from", + "type": "array", + "items": { + "type": "string" + } + }, + "profilereplication": { + "description": "Determings what to do when this peer sees messages broadcast by it's own profile (from another peer instance). Setting profilereplication to 'full' will cause this peer to automatically pin any data that is verifiably posted by the same peer", + "type": "string", + "enum": [ + "full" + ] + }, + "bootstrapaddrs": { + "description": "List of addresses to bootstrap qri peers on", + "anyOf": [ + {"type": "array"}, + {"type": "null"} + ], + "items": { + "type": "string" + } + } + } + }`) + return validate(schema, &cfg) +} + // // Validate confirms that the given settings will work, returning an error if not. // TODO - this validate method is a carry over from a previous incarnation that I'd like to // ressurrect as a method of conforming overrides to a steady-state while also validating diff --git a/config/p2p_test.go b/config/p2p_test.go index cedf2689a..fa6485a18 100644 --- a/config/p2p_test.go +++ b/config/p2p_test.go @@ -26,10 +26,17 @@ func TestP2PDecodePrivateKey(t *testing.T) { // run this test a few times to ensure default profile consistently generates // a valid PrivateKey for i := 0; i < 10; i++ { - p = P2P{}.Default() + p = DefaultP2P() _, err = p.DecodePrivateKey() if err != nil { t.Errorf("iter %d unexpected error: %s", i, err.Error()) } } } + +func TestP2PValidate(t *testing.T) { + err := DefaultP2P().Validate() + if err != nil { + t.Errorf("error validating default p2p: %s", err) + } +} diff --git a/p2p/node.go b/p2p/node.go index 122db6c06..e4307c56d 100644 --- a/p2p/node.go +++ b/p2p/node.go @@ -72,7 +72,7 @@ type QriNode struct { // NewQriNode creates a new node, providing no arguments will use // default configuration func NewQriNode(r repo.Repo, options ...func(o *config.P2P)) (node *QriNode, err error) { - cfg := config.P2P{}.Default() + cfg := config.DefaultP2P() for _, opt := range options { opt(cfg) }