@cryptotaxi247 / kubo / commits / d6aa9527f

pubsub cmd: switch to coreapi

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>

Łukasz Magiera committed Sep 11, 2018 at 12:52 UTC d6aa9527f2b101055df63fe887b8e3c21e8f28f0
4 files changed +104 -102
core/commands/pubsub.go
+35 -99
@@ -3,23 +3,16 @@ package commands
3 import (
4 "context"
5 "encoding/binary"
6 - "errors"
6 "fmt"
7 "io"
8 "net/http"
9 "sort"
11 - "sync"
12 - "time"
10
14 - core "github.com/ipfs/go-ipfs/core"
11 cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
12 e "github.com/ipfs/go-ipfs/core/commands/e"
13 + options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
14
18 - cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
19 - blocks "gx/ipfs/QmRcHuYzAyswytBuMF78rj3LTChYszomRFXNg4685ZN1WM/go-block-format"
20 - pstore "gx/ipfs/QmSJ36wcYQyEViJUWUEhJU81tw1KdakTKqLLHbvYbA9zDv/go-libp2p-peerstore"
15 cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
22 - floodsub "gx/ipfs/QmUK4h113Hh7bR2gPpsMcbUEbbzc7hspocmPi91Bmi69nH/go-libp2p-floodsub"
16 cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
17 )
18
@@ -48,6 +41,13 @@ const (
41 pubsubDiscoverOptionName = "discover"
42 )
43
44 +type pubsubMessage struct {
45 + From []byte `json:"from,omitempty"`
46 + Data []byte `json:"data,omitempty"`
47 + Seqno []byte `json:"seqno,omitempty"`
48 + TopicIDs []string `json:"topicIDs,omitempty"`
49 +}
50 +
51 var PubsubSubCmd = &cmds.Command{
52 Helptext: cmdkit.HelpText{
53 Tagline: "Subscribe to messages on a given topic.",
@@ -79,40 +79,16 @@ This command outputs data in the following encodings:
79 cmdkit.BoolOption(pubsubDiscoverOptionName, "try to discover other peers subscribed to the same topic"),
80 },
81 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
82 - n, err := cmdenv.GetNode(env)
82 + api, err := cmdenv.GetApi(env)
83 if err != nil {
84 return err
85 }
86
87 - // Must be online!
88 - if !n.OnlineMode() {
89 - return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
90 - }
91 -
92 - if n.Floodsub == nil {
93 - return fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use")
94 - }
95 -
87 topic := req.Arguments[0]
97 - sub, err := n.Floodsub.Subscribe(topic)
98 - if err != nil {
99 - return err
100 - }
101 - defer sub.Cancel()
102 -
88 discover, _ := req.Options[pubsubDiscoverOptionName].(bool)
104 - if discover {
105 - go func() {
106 - blk := blocks.NewBlock([]byte("floodsub:" + topic))
107 - err := n.Blocks.AddBlock(blk)
108 - if err != nil {
109 - log.Error("pubsub discovery: ", err)
110 - return
111 - }
112 -
113 - connectToPubSubPeers(req.Context, n, blk.Cid())
114 - }()
115 - }
89 +
90 + sub, err := api.PubSub().Subscribe(req.Context, topic, options.PubSub.Discover(discover))
91 + defer sub.Close()
92
93 if f, ok := res.(http.Flusher); ok {
94 f.Flush()
@@ -126,15 +102,17 @@ This command outputs data in the following encodings:
102 return err
103 }
104
129 - err = res.Emit(msg)
130 - if err != nil {
131 - return err
132 - }
105 + res.Emit(&pubsubMessage{
106 + Data: msg.Data(),
107 + From: []byte(msg.From()),
108 + Seqno: msg.Seq(),
109 + TopicIDs: msg.Topics(),
110 + })
111 }
112 },
113 Encoders: cmds.EncoderMap{
114 cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
137 - m, ok := v.(*floodsub.Message)
115 + m, ok := v.(*pubsubMessage)
116 if !ok {
117 return fmt.Errorf("unexpected type: %T", v)
118 }
@@ -143,7 +121,7 @@ This command outputs data in the following encodings:
121 return err
122 }),
123 "ndpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
146 - m, ok := v.(*floodsub.Message)
124 + m, ok := v.(*pubsubMessage)
125 if !ok {
126 return fmt.Errorf("unexpected type: %T", v)
127 }
@@ -153,7 +131,7 @@ This command outputs data in the following encodings:
131 return err
132 }),
133 "lenpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
156 - m, ok := v.(*floodsub.Message)
134 + m, ok := v.(*pubsubMessage)
135 if !ok {
136 return fmt.Errorf("unexpected type: %T", v)
137 }
@@ -166,31 +144,7 @@ This command outputs data in the following encodings:
144 return err
145 }),
146 },
169 - Type: floodsub.Message{},
170 -}
171 -
172 -func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid cid.Cid) {
173 - ctx, cancel := context.WithCancel(ctx)
174 - defer cancel()
175 -
176 - provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
177 - wg := &sync.WaitGroup{}
178 - for p := range provs {
179 - wg.Add(1)
180 - go func(pi pstore.PeerInfo) {
181 - defer wg.Done()
182 - ctx, cancel := context.WithTimeout(ctx, time.Second*10)
183 - defer cancel()
184 - err := n.PeerHost.Connect(ctx, pi)
185 - if err != nil {
186 - log.Info("pubsub discover: ", err)
187 - return
188 - }
189 - log.Info("connected to pubsub peer:", pi.ID)
190 - }(p)
191 - }
192 -
193 - wg.Wait()
147 + Type: pubsubMessage{},
148 }
149
150 var PubsubPubCmd = &cmds.Command{
@@ -210,20 +164,11 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
164 cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
165 },
166 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
213 - n, err := cmdenv.GetNode(env)
167 + api, err := cmdenv.GetApi(env)
168 if err != nil {
169 return err
170 }
171
218 - // Must be online!
219 - if !n.OnlineMode() {
220 - return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
221 - }
222 -
223 - if n.Floodsub == nil {
224 - return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
225 - }
226 -
172 topic := req.Arguments[0]
173
174 err = req.ParseBodyArgs()
@@ -232,7 +177,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
177 }
178
179 for _, data := range req.Arguments[1:] {
235 - if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
180 + if err := api.PubSub().Publish(req.Context, topic, []byte(data)); err != nil {
181 return err
182 }
183 }
@@ -254,21 +199,17 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
199 `,
200 },
201 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
257 - n, err := cmdenv.GetNode(env)
202 + api, err := cmdenv.GetApi(env)
203 if err != nil {
204 return err
205 }
206
262 - // Must be online!
263 - if !n.OnlineMode() {
264 - return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
265 - }
266 -
267 - if n.Floodsub == nil {
268 - return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
207 + l, err := api.PubSub().Ls(req.Context)
208 + if err != nil {
209 + return err
210 }
211
271 - return cmds.EmitOnce(res, stringList{n.Floodsub.GetTopics()})
212 + return cmds.EmitOnce(res, stringList{l})
213 },
214 Type: stringList{},
215 Encoders: cmds.EncoderMap{
@@ -308,26 +249,21 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
249 cmdkit.StringArg("topic", false, false, "topic to list connected peers of"),
250 },
251 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
311 - n, err := cmdenv.GetNode(env)
252 + api, err := cmdenv.GetApi(env)
253 if err != nil {
254 return err
255 }
256
316 - // Must be online!
317 - if !n.OnlineMode() {
318 - return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
319 - }
320 -
321 - if n.Floodsub == nil {
322 - return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use")
323 - }
324 -
257 var topic string
258 if len(req.Arguments) == 1 {
259 topic = req.Arguments[0]
260 }
261
330 - peers := n.Floodsub.ListPeers(topic)
262 + peers, err := api.PubSub().Peers(req.Context, options.PubSub.Topic(topic))
263 + if err != nil {
264 + return err
265 + }
266 +
267 list := &stringList{make([]string, 0, len(peers))}
268
269 for _, peer := range peers {
core/coreapi/coreapi.go
+4
@@ -16,8 +16,12 @@ package coreapi
16 import (
17 core "github.com/ipfs/go-ipfs/core"
18 coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
19 +
20 + logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
21 )
22
23 +var log = logging.Logger("core/coreapi")
24 +
25 type CoreAPI struct {
26 node *core.IpfsNode
27 }
core/coreapi/interface/pubsub.go
+7 -1
@@ -6,7 +6,7 @@ import (
6
7 options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
8
9 - peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
9 + peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
10 )
11
12 // PubSubSubscription is an active PubSub subscription
@@ -24,6 +24,12 @@ type PubSubMessage interface {
24
25 // Data returns the message body
26 Data() []byte
27 +
28 + // Seq returns message identifier
29 + Seq() []byte
30 +
31 + // Topics returns list of topics this message was set to
32 + Topics() []string
33 }
34
35 // PubSubAPI specifies the interface to PubSub
core/coreapi/pubsub.go
+58 -2
@@ -3,12 +3,18 @@ package coreapi
3 import (
4 "context"
5 "errors"
6 + "strings"
7 + "sync"
8 + "time"
9
10 + core "github.com/ipfs/go-ipfs/core"
11 coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
12 caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
13
10 - peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
11 - floodsub "gx/ipfs/QmY1L5krVk8dv8d74uESmJTXGpoigVYqBVxXXz1aS8aFSb/go-libp2p-floodsub"
14 + cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
15 + pstore "gx/ipfs/QmSJ36wcYQyEViJUWUEhJU81tw1KdakTKqLLHbvYbA9zDv/go-libp2p-peerstore"
16 + floodsub "gx/ipfs/QmUK4h113Hh7bR2gPpsMcbUEbbzc7hspocmPi91Bmi69nH/go-libp2p-floodsub"
17 + peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
18 )
19
20 type PubSubAPI CoreAPI
@@ -58,6 +64,8 @@ func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) er
64 }
65
66 func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
67 + options, err := caopts.PubSubSubscribeOptions(opts...)
68 +
69 if err := api.checkNode(); err != nil {
70 return nil, err
71 }
@@ -67,9 +75,45 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt
75 return nil, err
76 }
77
78 + if options.Discover {
79 + go func() {
80 + blk, err := api.core().Block().Put(ctx, strings.NewReader("floodsub:"+topic))
81 + if err != nil {
82 + log.Error("pubsub discovery: ", err)
83 + return
84 + }
85 +
86 + connectToPubSubPeers(ctx, api.node, blk.Path().Cid())
87 + }()
88 + }
89 +
90 return &pubSubSubscription{sub}, nil
91 }
92
93 +func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid cid.Cid) {
94 + ctx, cancel := context.WithCancel(ctx)
95 + defer cancel()
96 +
97 + provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
98 + wg := &sync.WaitGroup{}
99 + for p := range provs {
100 + wg.Add(1)
101 + go func(pi pstore.PeerInfo) {
102 + defer wg.Done()
103 + ctx, cancel := context.WithTimeout(ctx, time.Second*10)
104 + defer cancel()
105 + err := n.PeerHost.Connect(ctx, pi)
106 + if err != nil {
107 + log.Info("pubsub discover: ", err)
108 + return
109 + }
110 + log.Info("connected to pubsub peer:", pi.ID)
111 + }(p)
112 + }
113 +
114 + wg.Wait()
115 +}
116 +
117 func (api *PubSubAPI) checkNode() error {
118 if !api.node.OnlineMode() {
119 return coreiface.ErrOffline
@@ -103,3 +147,15 @@ func (msg *pubSubMessage) From() peer.ID {
147 func (msg *pubSubMessage) Data() []byte {
148 return msg.msg.Data
149 }
150 +
151 +func (msg *pubSubMessage) Seq() []byte {
152 + return msg.msg.Seqno
153 +}
154 +
155 +func (msg *pubSubMessage) Topics() []string {
156 + return msg.msg.TopicIDs
157 +}
158 +
159 +func (api *PubSubAPI) core() coreiface.CoreAPI {
160 + return (*CoreAPI)(api)
161 +}