master
go 146 lines 3.43 KB
Raw
1 package coreapi
2
3 import (
4 "context"
5 "errors"
6
7 coreiface "github.com/ipfs/kubo/core/coreiface"
8 caopts "github.com/ipfs/kubo/core/coreiface/options"
9 "github.com/ipfs/kubo/tracing"
10 pubsub "github.com/libp2p/go-libp2p-pubsub"
11 peer "github.com/libp2p/go-libp2p/core/peer"
12 routing "github.com/libp2p/go-libp2p/core/routing"
13 "go.opentelemetry.io/otel/attribute"
14 "go.opentelemetry.io/otel/trace"
15 )
16
17 type PubSubAPI CoreAPI
18
19 type pubSubSubscription struct {
20 subscription *pubsub.Subscription
21 }
22
23 type pubSubMessage struct {
24 msg *pubsub.Message
25 }
26
27 func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
28 _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Ls")
29 defer span.End()
30
31 _, err := api.checkNode()
32 if err != nil {
33 return nil, err
34 }
35
36 return api.pubSub.GetTopics(), nil
37 }
38
39 func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) {
40 _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Peers")
41 defer span.End()
42
43 _, err := api.checkNode()
44 if err != nil {
45 return nil, err
46 }
47
48 settings, err := caopts.PubSubPeersOptions(opts...)
49 if err != nil {
50 return nil, err
51 }
52
53 span.SetAttributes(attribute.String("topic", settings.Topic))
54
55 return api.pubSub.ListPeers(settings.Topic), nil
56 }
57
58 func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error {
59 _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Publish", trace.WithAttributes(attribute.String("topic", topic)))
60 defer span.End()
61
62 _, err := api.checkNode()
63 if err != nil {
64 return err
65 }
66
67 //nolint deprecated
68 return api.pubSub.Publish(topic, data)
69 }
70
71 func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
72 _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Subscribe", trace.WithAttributes(attribute.String("topic", topic)))
73 defer span.End()
74
75 // Parse the options to avoid introducing silent failures for invalid
76 // options. However, we don't currently have any use for them. The only
77 // subscription option, discovery, is now a no-op as it's handled by
78 // pubsub itself.
79 _, err := caopts.PubSubSubscribeOptions(opts...)
80 if err != nil {
81 return nil, err
82 }
83
84 _, err = api.checkNode()
85 if err != nil {
86 return nil, err
87 }
88
89 //nolint deprecated
90 sub, err := api.pubSub.Subscribe(topic)
91 if err != nil {
92 return nil, err
93 }
94
95 return &pubSubSubscription{sub}, nil
96 }
97
98 func (api *PubSubAPI) checkNode() (routing.Routing, error) {
99 if api.pubSub == nil {
100 return nil, errors.New("experimental pubsub feature not enabled, run daemon with --enable-pubsub-experiment to use")
101 }
102
103 err := api.checkOnline(false)
104 if err != nil {
105 return nil, err
106 }
107
108 return api.routing, nil
109 }
110
111 func (sub *pubSubSubscription) Close() error {
112 sub.subscription.Cancel()
113 return nil
114 }
115
116 func (sub *pubSubSubscription) Next(ctx context.Context) (coreiface.PubSubMessage, error) {
117 ctx, span := tracing.Span(ctx, "CoreAPI.PubSubSubscription", "Next")
118 defer span.End()
119
120 msg, err := sub.subscription.Next(ctx)
121 if err != nil {
122 return nil, err
123 }
124
125 return &pubSubMessage{msg}, nil
126 }
127
128 func (msg *pubSubMessage) From() peer.ID {
129 return peer.ID(msg.msg.From)
130 }
131
132 func (msg *pubSubMessage) Data() []byte {
133 return msg.msg.Data
134 }
135
136 func (msg *pubSubMessage) Seq() []byte {
137 return msg.msg.Seqno
138 }
139
140 func (msg *pubSubMessage) Topics() []string {
141 // TODO: handle breaking downstream changes by returning a single string.
142 if msg.msg.Topic == nil {
143 return nil
144 }
145 return []string{*msg.msg.Topic}
146 }