coreapi: Name API proposal
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Dec 10, 2017 at 23:15 UTC
027f498bc9faa37434c285b0293f5c9ba15aafb4
3 files changed
+171
core/coreapi/coreapi.go
+4
@@ -29,6 +29,10 @@ func (api *CoreAPI) Dag() coreiface.DagAPI {
29
return &DagAPI{api, nil}
30
}
31
32
+func (api *CoreAPI) Name() coreiface.NameAPI {
33
+ return (*NameAPI)(api)
34
+}
35
+
36
func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (coreiface.Node, error) {
37
p, err := api.ResolvePath(ctx, p)
38
if err != nil {
core/coreapi/interface/interface.go
+19
@@ -6,6 +6,7 @@ import (
6
"context"
7
"errors"
8
"io"
9
+ "time"
10
11
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
12
@@ -27,6 +28,11 @@ type Path interface {
28
type Node ipld.Node
29
type Link ipld.Link
30
31
+type IpnsEntry struct {
32
+ Name string
33
+ Value Path
34
+}
35
+
36
type Reader interface {
37
io.ReadSeeker
38
io.Closer
@@ -37,6 +43,7 @@ type CoreAPI interface {
43
// Unixfs returns an implementation of Unixfs API
44
Unixfs() UnixfsAPI
45
Dag() DagAPI
46
+ Name() NameAPI
47
48
// ResolvePath resolves the path using Unixfs resolver
49
ResolvePath(context.Context, Path) (Path, error)
@@ -90,6 +97,18 @@ type DagAPI interface {
97
WithDepth(depth int) options.DagTreeOption
98
}
99
100
+type NameAPI interface {
101
+ Publish(ctx context.Context, path Path, validTime time.Duration, key string) (*IpnsEntry, error)
102
+ Resolve(ctx context.Context, name string, recursive bool, local bool, nocache bool) (Path, error)
103
+}
104
+
105
+type KeyApi interface {
106
+ Generate(ctx context.Context, name string, algorithm string, size int) error
107
+ List(ctx context.Context) (map[string]string, error) //TODO: better key type?
108
+ Rename(ctx context.Context, oldName string, newName string) error
109
+ Remove(ctx context.Context, name string) error
110
+}
111
+
112
// type ObjectAPI interface {
113
// New() (cid.Cid, Object)
114
// Get(string) (Object, error)
core/coreapi/name.go
new
+148
@@ -0,0 +1,148 @@
1
+package coreapi
2
+
3
+import (
4
+ "context"
5
+ "errors"
6
+ "fmt"
7
+ "strings"
8
+ "time"
9
+
10
+ core "github.com/ipfs/go-ipfs/core"
11
+ coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
12
+ keystore "github.com/ipfs/go-ipfs/keystore"
13
+ namesys "github.com/ipfs/go-ipfs/namesys"
14
+ ipath "github.com/ipfs/go-ipfs/path"
15
+ offline "github.com/ipfs/go-ipfs/routing/offline"
16
+
17
+ peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
18
+ crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
19
+)
20
+
21
+type NameAPI CoreAPI
22
+
23
+func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, validTime time.Duration, key string) (*coreiface.IpnsEntry, error) {
24
+ n := api.node
25
+
26
+ if !n.OnlineMode() {
27
+ err := n.SetupOfflineRouting()
28
+ if err != nil {
29
+ return nil, err
30
+ }
31
+ }
32
+
33
+ if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
34
+ return nil, errors.New("cannot manually publish while IPNS is mounted")
35
+ }
36
+
37
+ if n.Identity == "" {
38
+ return nil, errors.New("identity not loaded")
39
+ }
40
+
41
+ pth, err := ipath.ParsePath(p.String())
42
+ if err != nil {
43
+ return nil, err
44
+ }
45
+
46
+ k, err := keylookup(n, key)
47
+ if err != nil {
48
+ return nil, err
49
+ }
50
+
51
+ eol := time.Now().Add(validTime)
52
+ err = n.Namesys.PublishWithEOL(ctx, k, pth, eol)
53
+ if err != nil {
54
+ return nil, err
55
+ }
56
+
57
+ pid, err := peer.IDFromPrivateKey(k)
58
+ if err != nil {
59
+ return nil, err
60
+ }
61
+
62
+ return &coreiface.IpnsEntry{
63
+ Name: pid.Pretty(),
64
+ Value: p,
65
+ }, nil
66
+}
67
+
68
+func (api *NameAPI) Resolve(ctx context.Context, name string, recursive bool, local bool, nocache bool) (coreiface.Path, error) {
69
+ n := api.node
70
+
71
+ if !n.OnlineMode() {
72
+ err := n.SetupOfflineRouting()
73
+ if err != nil {
74
+ return nil, err
75
+ }
76
+ }
77
+
78
+ var resolver namesys.Resolver = n.Namesys
79
+
80
+ if local && nocache {
81
+ return nil, errors.New("cannot specify both local and nocache")
82
+ }
83
+
84
+ if local {
85
+ offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
86
+ resolver = namesys.NewRoutingResolver(offroute, 0)
87
+ }
88
+
89
+ if nocache {
90
+ resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0)
91
+ }
92
+
93
+ depth := 1
94
+ if recursive {
95
+ depth = namesys.DefaultDepthLimit
96
+ }
97
+
98
+ if !strings.HasPrefix(name, "/ipns/") {
99
+ name = "/ipns/" + name
100
+ }
101
+
102
+ output, err := resolver.ResolveN(ctx, name, depth)
103
+ if err != nil {
104
+ return nil, err
105
+ }
106
+
107
+ return &path{path: output}, nil
108
+}
109
+
110
+func (api *NameAPI) core() coreiface.CoreAPI {
111
+ return (*CoreAPI)(api)
112
+}
113
+
114
+func keylookup(n *core.IpfsNode, k string) (crypto.PrivKey, error) {
115
+ res, err := n.GetKey(k)
116
+ if res != nil {
117
+ return res, nil
118
+ }
119
+
120
+ if err != nil && err != keystore.ErrNoSuchKey {
121
+ return nil, err
122
+ }
123
+
124
+ keys, err := n.Repo.Keystore().List()
125
+ if err != nil {
126
+ return nil, err
127
+ }
128
+
129
+ for _, key := range keys {
130
+ privKey, err := n.Repo.Keystore().Get(key)
131
+ if err != nil {
132
+ return nil, err
133
+ }
134
+
135
+ pubKey := privKey.GetPublic()
136
+
137
+ pid, err := peer.IDFromPublicKey(pubKey)
138
+ if err != nil {
139
+ return nil, err
140
+ }
141
+
142
+ if pid.Pretty() == k {
143
+ return privKey, nil
144
+ }
145
+ }
146
+
147
+ return nil, fmt.Errorf("no key by the given name or PeerID was found")
148
+}