writing files inside ipns works now! also implemented resolve cli command
Jeromy committed
Sep 26, 2014 at 12:08 UTC
6080944af992a0793df0917e55a86c8f8f5578c1
14 files changed
+144
-28
cmd/ipfs/ipfs.go
+1
@@ -53,6 +53,7 @@ Use "ipfs help <command>" for more information about a command.
53
cmdIpfsServe,
54
cmdIpfsRun,
55
cmdIpfsPub,
56
+ cmdIpfsResolve,
57
},
58
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
59
}
cmd/ipfs/resolve.go
new
+54
@@ -0,0 +1,54 @@
1
+package main
2
+
3
+import (
4
+ "fmt"
5
+ "os"
6
+ "time"
7
+
8
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
9
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
10
+ "github.com/jbenet/go-ipfs/core/commands"
11
+ "github.com/jbenet/go-ipfs/daemon"
12
+ u "github.com/jbenet/go-ipfs/util"
13
+)
14
+
15
+var cmdIpfsResolve = &commander.Command{
16
+ UsageLine: "resolve",
17
+ Short: "resolve an ipns link to a hash",
18
+ Long: `ipfs resolve <hash>... - Resolve hash.
19
+
20
+`,
21
+ Run: resolveCmd,
22
+ Flag: *flag.NewFlagSet("ipfs-resolve", flag.ExitOnError),
23
+}
24
+
25
+func resolveCmd(c *commander.Command, inp []string) error {
26
+ u.Debug = true
27
+ if len(inp) < 1 {
28
+ u.POut(c.Long)
29
+ return nil
30
+ }
31
+ conf, err := getConfigDir(c.Parent)
32
+ if err != nil {
33
+ return err
34
+ }
35
+
36
+ cmd := daemon.NewCommand()
37
+ cmd.Command = "resolve"
38
+ cmd.Args = inp
39
+ err = daemon.SendCommand(cmd, conf)
40
+ if err != nil {
41
+ now := time.Now()
42
+ // Resolve requires working DHT
43
+ n, err := localNode(conf, true)
44
+ if err != nil {
45
+ return err
46
+ }
47
+
48
+ took := time.Now().Sub(now)
49
+ fmt.Printf("localNode creation took %s\n", took.String())
50
+
51
+ return commands.Resolve(n, cmd.Args, cmd.Opts, os.Stdout)
52
+ }
53
+ return nil
54
+}
core/commands/publish.go
+2
-3
@@ -21,10 +21,9 @@ func Publish(n *core.IpfsNode, args []string, opts map[string]interface{}, out i
21
}
22
23
k := n.Identity.PrivKey
24
- val := u.Key(args[0])
24
25
pub := nsys.NewPublisher(n.DAG, n.Routing)
27
- err := pub.Publish(k, val)
26
+ err := pub.Publish(k, args[0])
27
if err != nil {
28
return err
29
}
@@ -33,7 +32,7 @@ func Publish(n *core.IpfsNode, args []string, opts map[string]interface{}, out i
32
if err != nil {
33
return err
34
}
36
- fmt.Fprintf(out, "Published %s to %s\n", val, u.Key(hash).Pretty())
35
+ fmt.Fprintf(out, "Published %s to %s\n", args[0], u.Key(hash).Pretty())
36
37
return nil
38
}
core/commands/resolve.go
new
+18
@@ -0,0 +1,18 @@
1
+package commands
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+
7
+ "github.com/jbenet/go-ipfs/core"
8
+)
9
+
10
+func Resolve(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
11
+ res, err := n.Namesys.Resolve(args[0])
12
+ if err != nil {
13
+ return err
14
+ }
15
+
16
+ fmt.Fprintf(out, "%s -> %s\n", args[0], res)
17
+ return nil
18
+}
daemon/daemon.go
+2
@@ -133,6 +133,8 @@ func (dl *DaemonListener) handleConnection(conn net.Conn) {
133
err = commands.Pin(dl.node, command.Args, command.Opts, conn)
134
case "publish":
135
err = commands.Publish(dl.node, command.Args, command.Opts, conn)
136
+ case "resolve":
137
+ err = commands.Resolve(dl.node, command.Args, command.Opts, conn)
138
default:
139
err = fmt.Errorf("Invalid Command: '%s'", command.Command)
140
}
fuse/ipns/ipns_unix.go
+24
-10
@@ -2,6 +2,7 @@ package ipns
2
3
import (
4
"fmt"
5
+ "io"
6
"io/ioutil"
7
"os"
8
"os/exec"
@@ -83,6 +84,11 @@ func CreateRoot(n *core.IpfsNode, keys []ci.PrivKey, ipfsroot string) (*Root, er
84
continue
85
}
86
87
+ if !u.IsValidHash(pointsTo) {
88
+ log.Critical("Got back bad data from namesys resolve! [%s]", pointsTo)
89
+ return nil, nil
90
+ }
91
+
92
node, err := n.Resolver.ResolvePath(pointsTo)
93
if err != nil {
94
log.Warning("Failed to resolve value from ipns entry in ipfs")
@@ -120,7 +126,7 @@ func (*Root) Attr() fuse.Attr {
126
127
// Lookup performs a lookup under this node.
128
func (s *Root) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
123
- log.Debug("ipns: Root Lookup: '%s'", name)
129
+ log.Debug("ipns: Root Lookup: '%s' [intr = %s]", name, intr.String())
130
switch name {
131
case "mach_kernel", ".hidden", "._.":
132
// Just quiet some log noise on OS X.
@@ -139,14 +145,14 @@ func (s *Root) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
145
return nd, nil
146
}
147
142
- log.Debug("ipns: Falling back to resolution.")
148
+ log.Debug("ipns: Falling back to resolution for [%s].", name)
149
resolved, err := s.Ipfs.Namesys.Resolve(name)
150
if err != nil {
151
log.Error("ipns: namesys resolve error: %s", err)
152
return nil, fuse.ENOENT
153
}
154
149
- return &Link{s.IpfsRoot + "/" + resolved}, nil
155
+ return &Link{s.IpfsRoot + "/" + u.Key(resolved).Pretty()}, nil
156
}
157
158
// ReadDir reads a particular directory. Disallowed for root.
@@ -221,7 +227,7 @@ func (s *Node) Attr() fuse.Attr {
227
228
// Lookup performs a lookup under this node.
229
func (s *Node) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
224
- log.Debug("ipns node Lookup '%s'", name)
230
+ log.Debug("ipns: node Lookup '%s'", name)
231
nd, err := s.Ipfs.Resolver.ResolveLinks(s.Nd, []string{name})
232
if err != nil {
233
// todo: make this error more versatile.
@@ -276,7 +282,7 @@ func (n *Node) Write(req *fuse.WriteRequest, resp *fuse.WriteResponse, intr fs.I
282
if n.dataBuf == nil {
283
n.dataBuf = new(bytes.Buffer)
284
}
279
- log.Debug("ipns Node Write: flags = %s, offset = %d, size = %d", req.Flags.String(), req.Offset, len(req.Data))
285
+ log.Debug("ipns: Node Write: flags = %s, offset = %d, size = %d", req.Flags.String(), req.Offset, len(req.Data))
286
if req.Offset == 0 {
287
n.dataBuf.Reset()
288
n.dataBuf.Write(req.Data)
@@ -298,11 +304,18 @@ func (n *Node) Flush(req *fuse.FlushRequest, intr fs.Intr) fuse.Error {
304
// but for now, since the buf is all in memory anyways...
305
err := imp.NewDagInNode(n.dataBuf, n.Nd)
306
if err != nil {
301
- log.Error("ipns Flush error: %s", err)
307
+ log.Error("ipns: Flush error: %s", err)
308
// return fuse.EVERYBAD
309
return fuse.ENODATA
310
}
311
312
+ read, err := mdag.NewDagReader(n.Nd, n.Ipfs.DAG)
313
+ if err != nil {
314
+ panic(err)
315
+ }
316
+
317
+ io.Copy(os.Stdout, read)
318
+
319
var root *Node
320
if n.nsRoot != nil {
321
root = n.nsRoot
@@ -312,13 +325,13 @@ func (n *Node) Flush(req *fuse.FlushRequest, intr fs.Intr) fuse.Error {
325
326
err = root.Nd.Update()
327
if err != nil {
315
- log.Error("ipns dag tree update failed: %s", err)
328
+ log.Error("ipns: dag tree update failed: %s", err)
329
return fuse.ENODATA
330
}
331
332
err = n.Ipfs.DAG.AddRecursive(root.Nd)
333
if err != nil {
321
- log.Critical("ipns Dag Add Error: %s", err)
334
+ log.Critical("ipns: Dag Add Error: %s", err)
335
}
336
337
n.changed = false
@@ -332,9 +345,9 @@ func (n *Node) Flush(req *fuse.FlushRequest, intr fs.Intr) fuse.Error {
345
}
346
log.Debug("Publishing changes!")
347
335
- err = n.Ipfs.Publisher.Publish(root.key, ndkey)
348
+ err = n.Ipfs.Publisher.Publish(root.key, ndkey.Pretty())
349
if err != nil {
337
- log.Error("ipns Publish Failed: %s", err)
350
+ log.Error("ipns: Publish Failed: %s", err)
351
}
352
}
353
return nil
@@ -433,5 +446,6 @@ func (l *Link) Attr() fuse.Attr {
446
}
447
448
func (l *Link) Readlink(req *fuse.ReadlinkRequest, intr fs.Intr) (string, fuse.Error) {
449
+ log.Debug("ReadLink: %s", l.Target)
450
return l.Target, nil
451
}
importer/importer.go
+1
-1
@@ -67,7 +67,7 @@ func NewDagInNode(r io.Reader, n *dag.Node) error {
67
68
blkChan := DefaultSplitter.Split(r)
69
first := <-blkChan
70
- n.Data = first
70
+ n.Data = dag.FilePBData(first)
71
72
for blk := range blkChan {
73
child := &dag.Node{Data: dag.WrapData(blk)}
namesys/nsresolver.go
+2
@@ -1,6 +1,8 @@
1
package namesys
2
3
type Resolver interface {
4
+ // Resolve returns a base58 encoded string
5
Resolve(string) (string, error)
6
+
7
Matches(string) bool
8
}
namesys/publisher.go
+3
-3
@@ -25,8 +25,8 @@ func NewPublisher(dag *mdag.DAGService, route routing.IpfsRouting) *IpnsPublishe
25
}
26
27
// Publish accepts a keypair and a value,
28
-func (p *IpnsPublisher) Publish(k ci.PrivKey, value u.Key) error {
29
- log.Debug("namesys: Publish %s", value.Pretty())
28
+func (p *IpnsPublisher) Publish(k ci.PrivKey, value string) error {
29
+ log.Debug("namesys: Publish %s", value)
30
ctx := context.TODO()
31
data, err := CreateEntryData(k, value)
32
if err != nil {
@@ -66,7 +66,7 @@ func (p *IpnsPublisher) Publish(k ci.PrivKey, value u.Key) error {
66
return nil
67
}
68
69
-func CreateEntryData(pk ci.PrivKey, val u.Key) ([]byte, error) {
69
+func CreateEntryData(pk ci.PrivKey, val string) ([]byte, error) {
70
entry := new(IpnsEntry)
71
sig, err := pk.Sign([]byte(val))
72
if err != nil {
namesys/resolve_test.go
+3
-5
@@ -7,9 +7,8 @@ import (
7
bs "github.com/jbenet/go-ipfs/blockservice"
8
ci "github.com/jbenet/go-ipfs/crypto"
9
mdag "github.com/jbenet/go-ipfs/merkledag"
10
- "github.com/jbenet/go-ipfs/net/swarm"
10
"github.com/jbenet/go-ipfs/peer"
12
- "github.com/jbenet/go-ipfs/routing/dht"
11
+ mock "github.com/jbenet/go-ipfs/routing/mock"
12
u "github.com/jbenet/go-ipfs/util"
13
)
14
@@ -17,9 +16,8 @@ func TestRoutingResolve(t *testing.T) {
16
local := &peer.Peer{
17
ID: []byte("testID"),
18
}
20
- net := swarm.NewSwarm(local)
19
lds := ds.NewMapDatastore()
22
- d := dht.NewDHT(local, net, lds)
20
+ d := mock.NewMockRouter(local, lds)
21
22
bserv, err := bs.NewBlockService(lds, nil)
23
if err != nil {
@@ -40,7 +38,7 @@ func TestRoutingResolve(t *testing.T) {
38
t.Fatal(err)
39
}
40
43
- err = pub.Publish(privk, u.Key("Hello"))
41
+ err = pub.Publish(privk, "Hello")
42
if err != nil {
43
t.Fatal(err)
44
}
namesys/routing.go
+1
@@ -35,6 +35,7 @@ func (r *RoutingResolver) Matches(name string) bool {
35
}
36
37
func (r *RoutingResolver) Resolve(name string) (string, error) {
38
+ log.Debug("RoutingResolve: '%s'", name)
39
ctx := context.TODO()
40
hash, err := mh.FromB58String(name)
41
if err != nil {
path/path.go
+15
-5
@@ -8,8 +8,11 @@ import (
8
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
9
merkledag "github.com/jbenet/go-ipfs/merkledag"
10
u "github.com/jbenet/go-ipfs/util"
11
+ "github.com/op/go-logging"
12
)
13
14
+var log = logging.MustGetLogger("path")
15
+
16
// Resolver provides path resolution to IPFS
17
// It has a pointer to a DAGService, which is uses to resolve nodes.
18
type Resolver struct {
@@ -20,7 +23,7 @@ type Resolver struct {
23
// path component as a hash (key) of the first node, then resolves
24
// all other components walking the links, with ResolveLinks.
25
func (s *Resolver) ResolvePath(fpath string) (*merkledag.Node, error) {
23
- u.DOut("Resolve: '%s'\n", fpath)
26
+ log.Debug("Resolve: '%s'", fpath)
27
fpath = path.Clean(fpath)
28
29
parts := strings.Split(fpath, "/")
@@ -66,10 +69,12 @@ func (s *Resolver) ResolveLinks(ndd *merkledag.Node, names []string) (
69
for _, name := range names {
70
71
var next u.Key
72
+ var nlink *merkledag.Link
73
// for each of the links in nd, the current object
74
for _, link := range nd.Links {
75
if link.Name == name {
76
next = u.Key(link.Hash)
77
+ nlink = link
78
break
79
}
80
}
@@ -80,10 +85,15 @@ func (s *Resolver) ResolveLinks(ndd *merkledag.Node, names []string) (
85
return nil, fmt.Errorf("no link named %q under %s", name, h2)
86
}
87
83
- // fetch object for link and assign to nd
84
- nd, err = s.DAG.Get(next)
85
- if err != nil {
86
- return nd, err
88
+ if nlink.Node == nil {
89
+ // fetch object for link and assign to nd
90
+ nd, err = s.DAG.Get(next)
91
+ if err != nil {
92
+ return nd, err
93
+ }
94
+ nlink.Node = nd
95
+ } else {
96
+ nd = nlink.Node
97
}
98
}
99
return
routing/dht/routing.go
+1
-1
@@ -18,7 +18,7 @@ import (
18
// PutValue adds value corresponding to given Key.
19
// This is the top level "Store" operation of the DHT
20
func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error {
21
- log.Debug("[%s] PutValue %v %v", dht.self.ID.Pretty(), key.Pretty(), value)
21
+ log.Debug("PutValue %s %v", key.Pretty(), value)
22
err := dht.putLocal(key, value)
23
if err != nil {
24
return err
util/util.go
+17
@@ -11,8 +11,17 @@ import (
11
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
12
b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
13
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
14
+ "github.com/op/go-logging"
15
)
16
17
+var format = "%{color}%{time} %{shortfile} %{level}: %{color:reset}%{message}"
18
+
19
+func init() {
20
+ backend := logging.NewLogBackend(os.Stderr, "", 0)
21
+ logging.SetBackend(backend)
22
+ logging.SetFormatter(logging.MustStringFormatter(format))
23
+}
24
+
25
// Debug is a global flag for debugging.
26
var Debug bool
27
@@ -42,6 +51,14 @@ func Hash(data []byte) (mh.Multihash, error) {
51
return mh.Sum(data, mh.SHA2_256, -1)
52
}
53
54
+func IsValidHash(s string) bool {
55
+ out := b58.Decode(s)
56
+ if out == nil || len(out) == 0 {
57
+ return false
58
+ }
59
+ return true
60
+}
61
+
62
// TildeExpansion expands a filename, which may begin with a tilde.
63
func TildeExpansion(filename string) (string, error) {
64
if strings.HasPrefix(filename, "~/") {