2021-04-28 20:10:44 +00:00
|
|
|
package relay
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-11-03 13:53:33 +00:00
|
|
|
"encoding/hex"
|
2021-04-28 20:10:44 +00:00
|
|
|
"errors"
|
2021-11-01 14:42:55 +00:00
|
|
|
"fmt"
|
2021-04-28 20:10:44 +00:00
|
|
|
"sync"
|
|
|
|
|
2022-10-19 19:39:32 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/host"
|
2023-02-08 14:20:40 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
2022-10-19 19:39:32 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/protocol"
|
2021-11-01 14:42:55 +00:00
|
|
|
"go.opencensus.io/stats"
|
|
|
|
"go.opencensus.io/tag"
|
2022-01-18 18:17:06 +00:00
|
|
|
"go.uber.org/zap"
|
2023-02-06 22:16:20 +00:00
|
|
|
proto "google.golang.org/protobuf/proto"
|
2021-04-28 20:10:44 +00:00
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
2021-07-29 22:08:53 +00:00
|
|
|
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
|
2022-11-03 13:53:33 +00:00
|
|
|
"github.com/waku-org/go-waku/logging"
|
2022-11-09 19:53:01 +00:00
|
|
|
v2 "github.com/waku-org/go-waku/waku/v2"
|
2023-03-04 21:51:51 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/hash"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/metrics"
|
|
|
|
waku_proto "github.com/waku-org/go-waku/waku/v2/protocol"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
2022-12-09 03:08:04 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/timesource"
|
2021-04-28 20:10:44 +00:00
|
|
|
)
|
|
|
|
|
2021-07-29 22:08:53 +00:00
|
|
|
const WakuRelayID_v200 = protocol.ID("/vac/waku/relay/2.0.0")
|
2021-11-10 14:28:45 +00:00
|
|
|
|
2021-11-19 16:19:48 +00:00
|
|
|
var DefaultWakuTopic string = waku_proto.DefaultPubsubTopic().String()
|
2021-04-28 20:10:44 +00:00
|
|
|
|
|
|
|
type WakuRelay struct {
|
2022-12-09 03:08:04 +00:00
|
|
|
host host.Host
|
2023-01-06 22:37:57 +00:00
|
|
|
opts []pubsub.Option
|
2022-12-09 03:08:04 +00:00
|
|
|
pubsub *pubsub.PubSub
|
|
|
|
timesource timesource.Timesource
|
2021-04-28 20:10:44 +00:00
|
|
|
|
2022-05-30 15:55:30 +00:00
|
|
|
log *zap.Logger
|
2022-01-18 18:17:06 +00:00
|
|
|
|
2021-11-06 22:46:58 +00:00
|
|
|
bcaster v2.Broadcaster
|
|
|
|
|
2021-12-06 08:43:00 +00:00
|
|
|
minPeersToPublish int
|
|
|
|
|
2021-11-06 22:46:58 +00:00
|
|
|
// TODO: convert to concurrent maps
|
2021-04-28 20:10:44 +00:00
|
|
|
topicsMutex sync.Mutex
|
2021-11-19 16:19:48 +00:00
|
|
|
wakuRelayTopics map[string]*pubsub.Topic
|
|
|
|
relaySubs map[string]*pubsub.Subscription
|
2021-11-01 14:42:55 +00:00
|
|
|
|
2021-11-06 22:46:58 +00:00
|
|
|
// TODO: convert to concurrent maps
|
2021-11-19 16:19:48 +00:00
|
|
|
subscriptions map[string][]*Subscription
|
2021-11-01 14:42:55 +00:00
|
|
|
subscriptionsMutex sync.Mutex
|
2023-02-08 14:20:40 +00:00
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
// TODO: convert to concurrent map with gc
|
|
|
|
msgCacheMutex sync.Mutex
|
|
|
|
msgCacheDeletions int
|
|
|
|
msgCache map[string]*pb.WakuMessage
|
|
|
|
shrinkCacheReq chan struct{}
|
2023-02-08 14:20:40 +00:00
|
|
|
|
2023-02-08 19:20:42 +00:00
|
|
|
ctx context.Context
|
2023-02-08 14:20:40 +00:00
|
|
|
cancel context.CancelFunc
|
|
|
|
wg sync.WaitGroup
|
2021-07-29 22:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func msgIdFn(pmsg *pubsub_pb.Message) string {
|
2023-03-04 21:51:51 +00:00
|
|
|
return string(hash.SHA256(pmsg.Data))
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// NewWakuRelay returns a new instance of a WakuRelay struct
|
2023-01-06 22:37:57 +00:00
|
|
|
func NewWakuRelay(h host.Host, bcaster v2.Broadcaster, minPeersToPublish int, timesource timesource.Timesource, log *zap.Logger, opts ...pubsub.Option) *WakuRelay {
|
2021-04-28 20:10:44 +00:00
|
|
|
w := new(WakuRelay)
|
|
|
|
w.host = h
|
2022-12-09 03:08:04 +00:00
|
|
|
w.timesource = timesource
|
2021-11-19 16:19:48 +00:00
|
|
|
w.wakuRelayTopics = make(map[string]*pubsub.Topic)
|
|
|
|
w.relaySubs = make(map[string]*pubsub.Subscription)
|
|
|
|
w.subscriptions = make(map[string][]*Subscription)
|
2021-11-01 14:42:55 +00:00
|
|
|
w.bcaster = bcaster
|
2021-12-06 08:43:00 +00:00
|
|
|
w.minPeersToPublish = minPeersToPublish
|
2023-02-08 14:20:40 +00:00
|
|
|
w.wg = sync.WaitGroup{}
|
2022-01-18 18:17:06 +00:00
|
|
|
w.log = log.Named("relay")
|
2021-07-29 22:08:53 +00:00
|
|
|
|
|
|
|
// default options required by WakuRelay
|
|
|
|
opts = append(opts, pubsub.WithMessageSignaturePolicy(pubsub.StrictNoSign))
|
|
|
|
opts = append(opts, pubsub.WithNoAuthor())
|
|
|
|
opts = append(opts, pubsub.WithMessageIdFn(msgIdFn))
|
|
|
|
opts = append(opts, pubsub.WithGossipSubProtocols(
|
|
|
|
[]protocol.ID{pubsub.GossipSubID_v11, pubsub.GossipSubID_v10, pubsub.FloodSubID, WakuRelayID_v200},
|
2021-10-08 13:50:56 +00:00
|
|
|
func(feat pubsub.GossipSubFeature, proto protocol.ID) bool {
|
2021-07-29 22:08:53 +00:00
|
|
|
switch feat {
|
2021-10-08 13:50:56 +00:00
|
|
|
case pubsub.GossipSubFeatureMesh:
|
|
|
|
return proto == pubsub.GossipSubID_v11 || proto == pubsub.GossipSubID_v10
|
|
|
|
case pubsub.GossipSubFeaturePX:
|
|
|
|
return proto == pubsub.GossipSubID_v11
|
2021-07-29 22:08:53 +00:00
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
2021-10-08 13:50:56 +00:00
|
|
|
},
|
2021-07-29 22:08:53 +00:00
|
|
|
))
|
2021-04-28 20:10:44 +00:00
|
|
|
|
2023-01-06 22:37:57 +00:00
|
|
|
w.opts = opts
|
|
|
|
|
|
|
|
return w
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *WakuRelay) Start(ctx context.Context) error {
|
2023-02-08 14:20:40 +00:00
|
|
|
w.wg.Wait()
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
2023-02-08 19:20:42 +00:00
|
|
|
w.ctx = ctx // TODO: create worker for creating subscriptions instead of storing context
|
2023-02-08 14:20:40 +00:00
|
|
|
w.cancel = cancel
|
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
w.shrinkCacheReq = make(chan struct{})
|
2023-02-08 14:20:40 +00:00
|
|
|
w.msgCache = make(map[string]*pb.WakuMessage, 1000)
|
|
|
|
|
|
|
|
w.wg.Add(1)
|
|
|
|
go w.cacheWorker(ctx)
|
|
|
|
|
2023-01-06 22:37:57 +00:00
|
|
|
ps, err := pubsub.NewGossipSub(ctx, w.host, w.opts...)
|
2021-04-28 20:10:44 +00:00
|
|
|
if err != nil {
|
2023-01-06 22:37:57 +00:00
|
|
|
return err
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
w.pubsub = ps
|
|
|
|
|
2022-01-18 18:17:06 +00:00
|
|
|
w.log.Info("Relay protocol started")
|
2023-01-06 22:37:57 +00:00
|
|
|
return nil
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 14:20:40 +00:00
|
|
|
func (w *WakuRelay) getMessageFromCache(topic string, id string) *pb.WakuMessage {
|
2023-02-08 23:49:15 +00:00
|
|
|
w.msgCacheMutex.Lock()
|
2023-02-08 14:20:40 +00:00
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
key := topic + id
|
|
|
|
msg := w.msgCache[key]
|
|
|
|
delete(w.msgCache, key)
|
|
|
|
w.msgCacheDeletions++
|
|
|
|
deleteCnt := w.msgCacheDeletions
|
|
|
|
w.msgCacheMutex.Unlock()
|
2023-02-08 19:20:42 +00:00
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
if deleteCnt > 1000 {
|
|
|
|
w.shrinkCacheReq <- struct{}{}
|
|
|
|
}
|
2023-02-08 19:20:42 +00:00
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
return msg
|
2023-02-08 14:20:40 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
func (w *WakuRelay) AddToCache(topic string, id string, msg *pb.WakuMessage) {
|
|
|
|
w.msgCacheMutex.Lock()
|
|
|
|
defer w.msgCacheMutex.Unlock()
|
|
|
|
|
|
|
|
key := topic + id
|
|
|
|
w.msgCache[key] = msg
|
2023-02-08 14:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *WakuRelay) cacheWorker(ctx context.Context) {
|
|
|
|
defer w.wg.Done()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
2023-02-08 23:49:15 +00:00
|
|
|
case <-w.shrinkCacheReq:
|
|
|
|
w.msgCacheMutex.Lock()
|
2023-02-08 14:20:40 +00:00
|
|
|
// Shrink msg cache to avoid oom
|
2023-02-08 23:49:15 +00:00
|
|
|
newMsgCache := make(map[string]*pb.WakuMessage, 1000)
|
|
|
|
for k, v := range w.msgCache {
|
|
|
|
newMsgCache[k] = v
|
2023-02-08 14:20:40 +00:00
|
|
|
}
|
2023-02-08 23:49:15 +00:00
|
|
|
w.msgCache = newMsgCache
|
|
|
|
w.msgCacheMutex.Unlock()
|
2023-02-08 14:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// PubSub returns the implementation of the pubsub system
|
2021-07-29 22:08:53 +00:00
|
|
|
func (w *WakuRelay) PubSub() *pubsub.PubSub {
|
2021-04-28 20:10:44 +00:00
|
|
|
return w.pubsub
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// Topics returns a list of all the pubsub topics currently subscribed to
|
2021-11-19 16:19:48 +00:00
|
|
|
func (w *WakuRelay) Topics() []string {
|
2021-04-28 20:10:44 +00:00
|
|
|
defer w.topicsMutex.Unlock()
|
|
|
|
w.topicsMutex.Lock()
|
|
|
|
|
2021-11-19 16:19:48 +00:00
|
|
|
var result []string
|
|
|
|
for topic := range w.relaySubs {
|
2021-04-28 20:10:44 +00:00
|
|
|
result = append(result, topic)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2022-05-30 15:55:30 +00:00
|
|
|
// SetPubSub is used to set an implementation of the pubsub system
|
2021-07-29 22:08:53 +00:00
|
|
|
func (w *WakuRelay) SetPubSub(pubSub *pubsub.PubSub) {
|
2021-04-28 20:10:44 +00:00
|
|
|
w.pubsub = pubSub
|
|
|
|
}
|
|
|
|
|
2021-11-19 16:19:48 +00:00
|
|
|
func (w *WakuRelay) upsertTopic(topic string) (*pubsub.Topic, error) {
|
2021-04-28 20:10:44 +00:00
|
|
|
defer w.topicsMutex.Unlock()
|
|
|
|
w.topicsMutex.Lock()
|
|
|
|
|
|
|
|
pubSubTopic, ok := w.wakuRelayTopics[topic]
|
|
|
|
if !ok { // Joins topic if node hasn't joined yet
|
|
|
|
newTopic, err := w.pubsub.Join(string(topic))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
w.wakuRelayTopics[topic] = newTopic
|
|
|
|
pubSubTopic = newTopic
|
|
|
|
}
|
|
|
|
return pubSubTopic, nil
|
|
|
|
}
|
|
|
|
|
2023-02-08 14:20:40 +00:00
|
|
|
func (w *WakuRelay) validatorFactory(pubsubTopic string) func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool {
|
|
|
|
return func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool {
|
|
|
|
msg := new(pb.WakuMessage)
|
|
|
|
err := proto.Unmarshal(message.Data, msg)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
w.AddToCache(pubsubTopic, message.ID, msg)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-19 16:19:48 +00:00
|
|
|
func (w *WakuRelay) subscribe(topic string) (subs *pubsub.Subscription, err error) {
|
2021-04-28 20:10:44 +00:00
|
|
|
sub, ok := w.relaySubs[topic]
|
|
|
|
if !ok {
|
|
|
|
pubSubTopic, err := w.upsertTopic(topic)
|
|
|
|
if err != nil {
|
2021-11-01 14:42:55 +00:00
|
|
|
return nil, err
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 14:20:40 +00:00
|
|
|
err = w.pubsub.RegisterTopicValidator(topic, w.validatorFactory(topic))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-04-28 20:10:44 +00:00
|
|
|
sub, err = pubSubTopic.Subscribe()
|
|
|
|
if err != nil {
|
2021-11-01 14:42:55 +00:00
|
|
|
return nil, err
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
w.relaySubs[topic] = sub
|
|
|
|
|
2022-07-24 20:51:42 +00:00
|
|
|
w.log.Info("subscribing to topic", zap.String("topic", sub.Topic()))
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
return sub, nil
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// PublishToTopic is used to broadcast a WakuMessage to a pubsub topic
|
2021-11-20 00:03:05 +00:00
|
|
|
func (w *WakuRelay) PublishToTopic(ctx context.Context, message *pb.WakuMessage, topic string) ([]byte, error) {
|
2021-04-28 20:10:44 +00:00
|
|
|
// Publish a `WakuMessage` to a PubSub topic.
|
|
|
|
if w.pubsub == nil {
|
2021-07-29 12:40:54 +00:00
|
|
|
return nil, errors.New("PubSub hasn't been set")
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if message == nil {
|
|
|
|
return nil, errors.New("message can't be null")
|
|
|
|
}
|
|
|
|
|
2021-12-06 08:43:00 +00:00
|
|
|
if !w.EnoughPeersToPublishToTopic(topic) {
|
2022-05-30 15:55:30 +00:00
|
|
|
return nil, errors.New("not enough peers to publish")
|
2021-12-06 08:43:00 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 20:01:52 +00:00
|
|
|
pubSubTopic, err := w.upsertTopic(topic)
|
2021-04-28 20:10:44 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out, err := proto.Marshal(message)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = pubSubTopic.Publish(ctx, out)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-03-04 21:51:51 +00:00
|
|
|
hash := message.Hash(topic)
|
2021-04-28 20:10:44 +00:00
|
|
|
|
2023-02-20 14:53:01 +00:00
|
|
|
w.log.Debug("waku.relay published", zap.String("hash", hex.EncodeToString(hash)))
|
2022-11-03 13:53:33 +00:00
|
|
|
|
2021-04-28 20:10:44 +00:00
|
|
|
return hash, nil
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// Publish is used to broadcast a WakuMessage to the default waku pubsub topic
|
2021-11-19 20:01:52 +00:00
|
|
|
func (w *WakuRelay) Publish(ctx context.Context, message *pb.WakuMessage) ([]byte, error) {
|
2021-11-20 00:03:05 +00:00
|
|
|
return w.PublishToTopic(ctx, message, DefaultWakuTopic)
|
2021-04-28 20:10:44 +00:00
|
|
|
}
|
2021-10-11 22:45:54 +00:00
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// Stop unmounts the relay protocol and stops all subscriptions
|
2021-10-11 22:45:54 +00:00
|
|
|
func (w *WakuRelay) Stop() {
|
2023-02-08 14:20:40 +00:00
|
|
|
if w.cancel == nil {
|
|
|
|
return // Not started
|
|
|
|
}
|
|
|
|
|
2021-10-11 22:45:54 +00:00
|
|
|
w.host.RemoveStreamHandler(WakuRelayID_v200)
|
2023-02-08 14:20:40 +00:00
|
|
|
|
|
|
|
w.cancel()
|
|
|
|
w.wg.Wait()
|
|
|
|
|
2023-02-08 23:49:15 +00:00
|
|
|
close(w.shrinkCacheReq)
|
2023-02-08 14:20:40 +00:00
|
|
|
|
|
|
|
w.msgCache = nil
|
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
w.subscriptionsMutex.Lock()
|
|
|
|
defer w.subscriptionsMutex.Unlock()
|
|
|
|
|
|
|
|
for _, topic := range w.Topics() {
|
|
|
|
for _, sub := range w.subscriptions[topic] {
|
|
|
|
sub.Unsubscribe()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.subscriptions = nil
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// EnoughPeersToPublish returns whether there are enough peers connected in the default waku pubsub topic
|
2021-12-06 08:43:00 +00:00
|
|
|
func (w *WakuRelay) EnoughPeersToPublish() bool {
|
|
|
|
return w.EnoughPeersToPublishToTopic(DefaultWakuTopic)
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// EnoughPeersToPublish returns whether there are enough peers connected in a pubsub topic
|
2021-12-06 08:43:00 +00:00
|
|
|
func (w *WakuRelay) EnoughPeersToPublishToTopic(topic string) bool {
|
|
|
|
return len(w.PubSub().ListPeers(topic)) >= w.minPeersToPublish
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// SubscribeToTopic returns a Subscription to receive messages from a pubsub topic
|
2021-11-20 00:03:05 +00:00
|
|
|
func (w *WakuRelay) SubscribeToTopic(ctx context.Context, topic string) (*Subscription, error) {
|
2021-11-19 20:01:52 +00:00
|
|
|
sub, err := w.subscribe(topic)
|
2021-11-01 14:42:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create client subscription
|
|
|
|
subscription := new(Subscription)
|
|
|
|
subscription.closed = false
|
|
|
|
subscription.C = make(chan *waku_proto.Envelope, 1024) // To avoid blocking
|
|
|
|
subscription.quit = make(chan struct{})
|
|
|
|
|
|
|
|
w.subscriptionsMutex.Lock()
|
|
|
|
defer w.subscriptionsMutex.Unlock()
|
|
|
|
|
2021-11-19 20:01:52 +00:00
|
|
|
w.subscriptions[topic] = append(w.subscriptions[topic], subscription)
|
2021-11-01 14:42:55 +00:00
|
|
|
|
|
|
|
if w.bcaster != nil {
|
2022-04-25 19:31:26 +00:00
|
|
|
w.bcaster.Register(&topic, subscription.C)
|
2021-11-01 14:42:55 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 19:20:42 +00:00
|
|
|
w.wg.Add(1)
|
2022-12-11 00:08:25 +00:00
|
|
|
go w.subscribeToTopic(ctx, topic, subscription, sub)
|
2021-11-01 14:42:55 +00:00
|
|
|
|
|
|
|
return subscription, nil
|
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// SubscribeToTopic returns a Subscription to receive messages from the default waku pubsub topic
|
2021-11-19 20:01:52 +00:00
|
|
|
func (w *WakuRelay) Subscribe(ctx context.Context) (*Subscription, error) {
|
2021-11-20 00:03:05 +00:00
|
|
|
return w.SubscribeToTopic(ctx, DefaultWakuTopic)
|
2021-11-19 20:01:52 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 21:08:24 +00:00
|
|
|
// Unsubscribe closes a subscription to a pubsub topic
|
2021-11-19 16:19:48 +00:00
|
|
|
func (w *WakuRelay) Unsubscribe(ctx context.Context, topic string) error {
|
2022-07-24 20:51:42 +00:00
|
|
|
sub, ok := w.relaySubs[topic]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("not subscribed to topic")
|
2021-11-06 10:49:47 +00:00
|
|
|
}
|
2022-07-24 20:51:42 +00:00
|
|
|
w.log.Info("unsubscribing from topic", zap.String("topic", sub.Topic()))
|
2021-11-06 10:49:47 +00:00
|
|
|
|
|
|
|
for _, sub := range w.subscriptions[topic] {
|
|
|
|
sub.Unsubscribe()
|
|
|
|
}
|
|
|
|
|
|
|
|
w.relaySubs[topic].Cancel()
|
|
|
|
delete(w.relaySubs, topic)
|
|
|
|
|
|
|
|
err := w.wakuRelayTopics[topic].Close()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
delete(w.wakuRelayTopics, topic)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
func (w *WakuRelay) nextMessage(ctx context.Context, sub *pubsub.Subscription) <-chan *pubsub.Message {
|
|
|
|
msgChannel := make(chan *pubsub.Message, 1024)
|
|
|
|
go func(msgChannel chan *pubsub.Message) {
|
2021-11-06 10:49:47 +00:00
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
2022-01-18 18:17:06 +00:00
|
|
|
w.log.Debug("recovered msgChannel")
|
2021-11-06 10:49:47 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
for {
|
|
|
|
msg, err := sub.Next(ctx)
|
|
|
|
if err != nil {
|
2023-01-06 22:37:57 +00:00
|
|
|
if !errors.Is(err, context.Canceled) {
|
|
|
|
w.log.Error("getting message from subscription", zap.Error(err))
|
|
|
|
}
|
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
sub.Cancel()
|
|
|
|
close(msgChannel)
|
2021-11-19 16:19:48 +00:00
|
|
|
for _, subscription := range w.subscriptions[sub.Topic()] {
|
2021-11-01 14:42:55 +00:00
|
|
|
subscription.Unsubscribe()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
msgChannel <- msg
|
|
|
|
}
|
|
|
|
}(msgChannel)
|
|
|
|
return msgChannel
|
|
|
|
}
|
|
|
|
|
2023-02-08 19:20:42 +00:00
|
|
|
func (w *WakuRelay) subscribeToTopic(userCtx context.Context, pubsubTopic string, subscription *Subscription, sub *pubsub.Subscription) {
|
|
|
|
defer w.wg.Done()
|
|
|
|
|
|
|
|
ctx, err := tag.New(w.ctx, tag.Insert(metrics.KeyType, "relay"))
|
2021-11-01 14:42:55 +00:00
|
|
|
if err != nil {
|
2022-05-30 15:55:30 +00:00
|
|
|
w.log.Error("creating tag map", zap.Error(err))
|
2021-11-01 14:42:55 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-08 19:20:42 +00:00
|
|
|
subChannel := w.nextMessage(w.ctx, sub)
|
2021-11-01 14:42:55 +00:00
|
|
|
for {
|
|
|
|
select {
|
2023-02-08 19:20:42 +00:00
|
|
|
case <-userCtx.Done():
|
|
|
|
return
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
2021-11-01 14:42:55 +00:00
|
|
|
case <-subscription.quit:
|
2022-04-25 19:31:26 +00:00
|
|
|
func(topic string) {
|
2022-02-23 15:08:27 +00:00
|
|
|
subscription.Lock()
|
|
|
|
defer subscription.Unlock()
|
|
|
|
|
|
|
|
if subscription.closed {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
subscription.closed = true
|
|
|
|
if w.bcaster != nil {
|
2022-04-25 19:31:26 +00:00
|
|
|
<-w.bcaster.WaitUnregister(&topic, subscription.C) // Remove from broadcast list
|
2022-02-23 15:08:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
close(subscription.C)
|
2023-02-08 14:20:40 +00:00
|
|
|
}(pubsubTopic)
|
2021-11-01 14:42:55 +00:00
|
|
|
// TODO: if there are no more relay subscriptions, close the pubsub subscription
|
|
|
|
case msg := <-subChannel:
|
2021-11-06 10:49:47 +00:00
|
|
|
if msg == nil {
|
|
|
|
return
|
|
|
|
}
|
2021-11-01 14:42:55 +00:00
|
|
|
stats.Record(ctx, metrics.Messages.M(1))
|
|
|
|
|
2023-02-08 14:20:40 +00:00
|
|
|
wakuMessage := w.getMessageFromCache(pubsubTopic, msg.ID)
|
|
|
|
envelope := waku_proto.NewEnvelope(wakuMessage, w.timesource.Now().UnixNano(), string(pubsubTopic))
|
2021-11-01 14:42:55 +00:00
|
|
|
|
2023-02-20 14:53:01 +00:00
|
|
|
w.log.Debug("waku.relay received", logging.HexString("hash", envelope.Hash()))
|
2022-11-03 13:53:33 +00:00
|
|
|
|
2021-11-01 14:42:55 +00:00
|
|
|
if w.bcaster != nil {
|
|
|
|
w.bcaster.Submit(envelope)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 22:45:54 +00:00
|
|
|
}
|