2020-11-18 19:53:52 +00:00
|
|
|
package pubsub
|
2020-10-20 18:18:36 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-12-07 15:22:47 +00:00
|
|
|
"time"
|
2020-10-20 18:18:36 +00:00
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
"github.com/fxamacker/cbor/v2"
|
|
|
|
|
2021-06-02 21:19:52 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/host"
|
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
2020-10-20 18:18:36 +00:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
2020-10-21 20:36:05 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2020-10-20 18:18:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type PubSubRouter struct {
|
2020-11-18 19:53:52 +00:00
|
|
|
node host.Host
|
|
|
|
Pubsub *pubsub.PubSub
|
|
|
|
context context.Context
|
|
|
|
contextCancel context.CancelFunc
|
|
|
|
serviceSubscription *pubsub.Subscription
|
2021-06-02 21:19:52 +00:00
|
|
|
handlers map[PubSubMessageType][]Handler
|
2020-12-04 18:30:03 +00:00
|
|
|
oracleTopicName string
|
|
|
|
oracleTopic *pubsub.Topic
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 21:19:52 +00:00
|
|
|
type Handler func(message *PubSubMessage)
|
|
|
|
|
2020-12-07 15:22:47 +00:00
|
|
|
func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubRouter {
|
2020-10-20 18:18:36 +00:00
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
psr := &PubSubRouter{
|
2020-10-21 19:54:40 +00:00
|
|
|
node: h,
|
2020-10-20 18:18:36 +00:00
|
|
|
context: ctx,
|
|
|
|
contextCancel: ctxCancel,
|
2021-06-02 21:19:52 +00:00
|
|
|
handlers: make(map[PubSubMessageType][]Handler),
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
|
2020-12-07 15:22:47 +00:00
|
|
|
var pbOptions []pubsub.Option
|
|
|
|
|
|
|
|
if isBootstrap {
|
|
|
|
// turn off the mesh in bootstrappers -- only do gossip and PX
|
|
|
|
pubsub.GossipSubD = 0
|
|
|
|
pubsub.GossipSubDscore = 0
|
|
|
|
pubsub.GossipSubDlo = 0
|
|
|
|
pubsub.GossipSubDhi = 0
|
|
|
|
pubsub.GossipSubDout = 0
|
|
|
|
pubsub.GossipSubDlazy = 64
|
|
|
|
pubsub.GossipSubGossipFactor = 0.25
|
|
|
|
pubsub.GossipSubPruneBackoff = 5 * time.Minute
|
|
|
|
// turn on PX
|
|
|
|
pbOptions = append(pbOptions, pubsub.WithPeerExchange(true))
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:30:03 +00:00
|
|
|
pb, err := pubsub.NewGossipSub(
|
2020-10-21 20:36:05 +00:00
|
|
|
context.TODO(),
|
2020-12-04 18:30:03 +00:00
|
|
|
psr.node,
|
2020-12-07 15:22:47 +00:00
|
|
|
pbOptions...,
|
2020-10-20 18:18:36 +00:00
|
|
|
)
|
2020-12-07 15:22:47 +00:00
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
2020-12-07 15:22:47 +00:00
|
|
|
logrus.Fatalf("Error occurred when initializing PubSub subsystem: %v", err)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
|
2020-12-04 18:30:03 +00:00
|
|
|
psr.oracleTopicName = oracleTopic
|
2020-11-18 19:53:52 +00:00
|
|
|
topic, err := pb.Join(oracleTopic)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
2020-12-07 15:22:47 +00:00
|
|
|
logrus.Fatalf("Error occurred when subscribing to service topic: %v", err)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
2020-11-18 19:53:52 +00:00
|
|
|
|
|
|
|
subscription, err := topic.Subscribe()
|
|
|
|
psr.serviceSubscription = subscription
|
2020-10-28 17:35:56 +00:00
|
|
|
psr.Pubsub = pb
|
2020-12-04 18:30:03 +00:00
|
|
|
psr.oracleTopic = topic
|
2020-10-20 18:18:36 +00:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-psr.context.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
msg, err := subscription.Next(psr.context)
|
|
|
|
if err != nil {
|
2020-12-07 15:22:47 +00:00
|
|
|
logrus.Warnf("Failed to receive pubsub message: %v", err)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
psr.handleMessage(msg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return psr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (psr *PubSubRouter) handleMessage(p *pubsub.Message) {
|
|
|
|
senderPeerID, err := peer.IDFromBytes(p.From)
|
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Warn("Unable to decode sender peer ID! " + err.Error())
|
2020-10-20 18:18:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
// We can receive our own messages when sending to the topic. So we should drop them.
|
2020-10-21 19:54:40 +00:00
|
|
|
if senderPeerID == psr.node.ID() {
|
2020-10-20 18:18:36 +00:00
|
|
|
return
|
|
|
|
}
|
2021-06-02 21:19:52 +00:00
|
|
|
var message PubSubMessage
|
2020-11-18 19:53:52 +00:00
|
|
|
err = cbor.Unmarshal(p.Data, &message)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Warn("Unable to decode message data! " + err.Error())
|
2020-10-20 18:18:36 +00:00
|
|
|
return
|
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
message.From = senderPeerID
|
2020-10-20 18:18:36 +00:00
|
|
|
handlers, ok := psr.handlers[message.Type]
|
|
|
|
if !ok {
|
2020-11-15 13:46:58 +00:00
|
|
|
logrus.Warn("Dropping message " + string(message.Type) + " because we don't have any handlers!")
|
2020-10-20 18:18:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, v := range handlers {
|
2020-10-21 19:54:40 +00:00
|
|
|
go v(&message)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-02 21:19:52 +00:00
|
|
|
func (psr *PubSubRouter) Hook(messageType PubSubMessageType, handler Handler) {
|
2020-12-02 14:09:46 +00:00
|
|
|
_, ok := psr.handlers[messageType]
|
2020-10-20 18:18:36 +00:00
|
|
|
if !ok {
|
2020-12-02 14:09:46 +00:00
|
|
|
psr.handlers[messageType] = []Handler{}
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
2020-12-02 14:09:46 +00:00
|
|
|
psr.handlers[messageType] = append(psr.handlers[messageType], handler)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 21:19:52 +00:00
|
|
|
func (psr *PubSubRouter) BroadcastToServiceTopic(msg *PubSubMessage) error {
|
2020-11-18 19:53:52 +00:00
|
|
|
data, err := cbor.Marshal(msg)
|
2020-10-21 19:54:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-04 18:30:03 +00:00
|
|
|
err = psr.oracleTopic.Publish(context.TODO(), data)
|
2020-10-21 19:54:40 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
func (psr *PubSubRouter) Shutdown() {
|
|
|
|
psr.contextCancel()
|
|
|
|
}
|