-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add in a default file hash and cleaned up init function a bit #266
Changes from 2 commits
ab805f3
e857a5b
7596bcc
ab09c36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,22 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" | ||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" | ||
config "github.com/jbenet/go-ipfs/config" | ||
core "github.com/jbenet/go-ipfs/core" | ||
ci "github.com/jbenet/go-ipfs/crypto" | ||
imp "github.com/jbenet/go-ipfs/importer" | ||
chunk "github.com/jbenet/go-ipfs/importer/chunk" | ||
peer "github.com/jbenet/go-ipfs/peer" | ||
updates "github.com/jbenet/go-ipfs/updates" | ||
u "github.com/jbenet/go-ipfs/util" | ||
) | ||
|
||
|
@@ -33,6 +39,66 @@ func init() { | |
cmdIpfsInit.Flag.String("d", "", "Change default datastore location") | ||
} | ||
|
||
var defaultPeers = []*config.BootstrapPeer{ | ||
&config.BootstrapPeer{ | ||
// mars.i.ipfs.io | ||
PeerID: "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", | ||
Address: "/ip4/104.131.131.82/tcp/4001", | ||
}, | ||
} | ||
|
||
func datastoreConfig(dspath string) (config.Datastore, error) { | ||
ds := config.Datastore{} | ||
if len(dspath) == 0 { | ||
var err error | ||
dspath, err = config.DataStorePath("") | ||
if err != nil { | ||
return ds, err | ||
} | ||
} | ||
ds.Path = dspath | ||
ds.Type = "leveldb" | ||
|
||
// Construct the data store if missing | ||
if err := os.MkdirAll(dspath, os.ModePerm); err != nil { | ||
return ds, err | ||
} | ||
|
||
// Check the directory is writeable | ||
if f, err := os.Create(filepath.Join(dspath, "._check_writeable")); err == nil { | ||
os.Remove(f.Name()) | ||
} else { | ||
return ds, errors.New("Datastore '" + dspath + "' is not writeable") | ||
} | ||
|
||
return ds, nil | ||
} | ||
|
||
func identityConfig(nbits int) (config.Identity, error) { | ||
ident := config.Identity{} | ||
fmt.Println("generating key pair...") | ||
sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) | ||
if err != nil { | ||
return ident, err | ||
} | ||
|
||
// currently storing key unencrypted. in the future we need to encrypt it. | ||
// TODO(security) | ||
skbytes, err := sk.Bytes() | ||
if err != nil { | ||
return ident, err | ||
} | ||
ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes) | ||
|
||
id, err := peer.IDFromPubKey(pk) | ||
if err != nil { | ||
return ident, err | ||
} | ||
ident.PeerID = id.Pretty() | ||
|
||
return ident, nil | ||
} | ||
|
||
func initCmd(c *commander.Command, inp []string) error { | ||
configpath, err := getConfigDir(c.Parent) | ||
if err != nil { | ||
|
@@ -62,30 +128,12 @@ func initCmd(c *commander.Command, inp []string) error { | |
} | ||
cfg := new(config.Config) | ||
|
||
cfg.Datastore = config.Datastore{} | ||
if len(dspath) == 0 { | ||
dspath, err = config.DataStorePath("") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
cfg.Datastore.Path = dspath | ||
cfg.Datastore.Type = "leveldb" | ||
|
||
// Construct the data store if missing | ||
if err := os.MkdirAll(dspath, os.ModePerm); err != nil { | ||
// setup the datastore | ||
cfg.Datastore, err = datastoreConfig(dspath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Check the directory is writeable | ||
if f, err := os.Create(filepath.Join(dspath, "._check_writeable")); err == nil { | ||
os.Remove(f.Name()) | ||
} else { | ||
return errors.New("Datastore '" + dspath + "' is not writeable") | ||
} | ||
|
||
cfg.Identity = config.Identity{} | ||
|
||
// setup the node addresses. | ||
cfg.Addresses = config.Addresses{ | ||
Swarm: "/ip4/0.0.0.0/tcp/4001", | ||
|
@@ -106,42 +154,47 @@ func initCmd(c *commander.Command, inp []string) error { | |
return errors.New("Bitsize less than 1024 is considered unsafe.") | ||
} | ||
|
||
u.POut("generating key pair\n") | ||
sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) | ||
cfg.Identity, err = identityConfig(nbits) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// currently storing key unencrypted. in the future we need to encrypt it. | ||
// TODO(security) | ||
skbytes, err := sk.Bytes() | ||
if err != nil { | ||
return err | ||
// Use these hardcoded bootstrap peers for now. | ||
cfg.Bootstrap = defaultPeers | ||
|
||
// tracking ipfs version used to generate the init folder | ||
// and adding update checker default setting. | ||
cfg.Version = config.Version{ | ||
Check: "error", | ||
Current: updates.Version, | ||
} | ||
cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes) | ||
|
||
id, err := peer.IDFromPubKey(pk) | ||
err = config.WriteConfigFile(filename, cfg) | ||
if err != nil { | ||
return err | ||
} | ||
cfg.Identity.PeerID = id.Pretty() | ||
u.POut("peer identity: %s\n", id.Pretty()) | ||
|
||
// Use these hardcoded bootstrap peers for now. | ||
cfg.Bootstrap = []*config.BootstrapPeer{ | ||
&config.BootstrapPeer{ | ||
// mars.i.ipfs.io | ||
PeerID: "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", | ||
Address: "/ip4/104.131.131.82/tcp/4001", | ||
}, | ||
nd, err := core.NewIpfsNode(cfg, false) | ||
if err != nil { | ||
return err | ||
} | ||
defer nd.Close() | ||
|
||
// tracking ipfs version used to generate the init folder and adding update checker default setting. | ||
cfg.Version = config.VersionDefaultValue() | ||
// Set up default file | ||
msg := `Hello and Welcome to IPFS! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This message hasn't been applied to the new PR @whyrusleeping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @maybebtc Which one is the new PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
If you're seeing this, that means that you have successfully | ||
installed ipfs and are now interfacing with the wonderful | ||
world of DAGs and hashes! | ||
` | ||
reader := bytes.NewBufferString(msg) | ||
|
||
err = config.WriteConfigFile(filename, cfg) | ||
defnd, err := imp.BuildDagFromReader(reader, nd.DAG, nd.Pinning.GetManual(), chunk.DefaultSplitter) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
k, _ := defnd.Key() | ||
fmt.Printf("Default file key: %s\n", k) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
|
@@ -9,7 +10,10 @@ import ( | |
|
||
cmds "github.com/jbenet/go-ipfs/commands" | ||
config "github.com/jbenet/go-ipfs/config" | ||
core "github.com/jbenet/go-ipfs/core" | ||
ci "github.com/jbenet/go-ipfs/crypto" | ||
imp "github.com/jbenet/go-ipfs/importer" | ||
chunk "github.com/jbenet/go-ipfs/importer/chunk" | ||
peer "github.com/jbenet/go-ipfs/peer" | ||
u "github.com/jbenet/go-ipfs/util" | ||
) | ||
|
@@ -114,6 +118,29 @@ func doInit(configRoot string, dspathOverride string, force bool, nBitsForKeypai | |
if err != nil { | ||
return err | ||
} | ||
|
||
nd, err := core.NewIpfsNode(&conf, false) | ||
if err != nil { | ||
return err | ||
} | ||
defer nd.Close() | ||
|
||
// Set up default file | ||
msg := `Hello and Welcome to IPFS! | ||
If you're seeing this, that means that you have successfully | ||
installed ipfs and are now interfacing with the wonderful | ||
world of DAGs and hashes! | ||
` | ||
reader := bytes.NewBufferString(msg) | ||
|
||
defnd, err := imp.BuildDagFromReader(reader, nd.DAG, nd.Pinning.GetManual(), chunk.DefaultSplitter) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
k, _ := defnd.Key() | ||
fmt.Printf("Default file key: %s\n", k) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. though init is local, we've moved to not have any Printf anywhere except main. Return the string and have it printed as usual cmd output There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nevermind, init already prints this way... >.< |
||
|
||
return nil | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the node need to be closed everywhere it is instantiated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would feel better if it was, technically it doesnt need to be, because in most of our uses, no longer needing the node means closing down the program and letting the operating system clean up, but Im always slightly paranoid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see. we may know better, but we can't rely on our individual knowledge. developers who import our library and instantiate nodes programmatically may have other plans. the system needs to speak for itself.
perhaps we should communicate this through the function signature:
node, cancel, err := core.Node(...)
where the implementation does the following:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed.
👎 leaking underlying libs and abstractions is not clean. This is what the
Closer
interface is for.Internally, that Close method can do whatever, but our interfaces do not leak out the entrails of our implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's incorrect. cancel is a
func()
. That is not leaking an abstraction. It's explanatory, and forces the caller to make a conscious decision to ignore shutdown. Much safer practice than depending on the programmer to calldefer Close()
at all call sites.Design the system to minimize programmer error. This only increases in importance as the system grows.
people might forget to close => make it impossible to forget
We have empirical evidence that the existing interface is easy to use incorrectly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ehh.... im still not super sold on the returning a cancel func idea... It doesnt feel like idiomatic Go to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair. I stand by merits of the approach, but accept and acknowledge its downsides. I'm not sold either. I'm okay with continuing to manage the node the same way we do files and locks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a way, its the same as making people remember to close a file, or a socket
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that is a nice property. An approach like:
Might avoid making mistakes a bit more. But note it doesn't actually force the user to deal with the return value.
doesn't even get a warning. So it's not an 100% solution.
The added complexity and leaking of abstractions is that if
cancel
its not going to be called in the same function than you have to continue leaking it out, or add it to a new object:I dont think passing these cancel functions around is a good idea. I'd be curious to see what go-nuts have to say about it.
This is not critical. Let's keep it in mind and move on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.