149 lines
3.5 KiB
Go
149 lines
3.5 KiB
Go
package common
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
|
|
"cloud.o-forge.io/core/oc-lib/models/peer"
|
|
"cloud.o-forge.io/core/oc-lib/tools"
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
pp "github.com/libp2p/go-libp2p/core/peer"
|
|
)
|
|
|
|
type Event struct {
|
|
Type string `json:"type"`
|
|
From string `json:"from"` // peerID
|
|
|
|
User string
|
|
|
|
DataType int64 `json:"datatype"`
|
|
Timestamp int64 `json:"ts"`
|
|
Payload []byte `json:"payload"`
|
|
Signature []byte `json:"sig"`
|
|
}
|
|
|
|
func NewEvent(name string, from string, dt *tools.DataType, user string, payload []byte) *Event {
|
|
priv, err := LoadKeyFromFile(false) // your node private key
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
evt := &Event{
|
|
Type: name,
|
|
From: from,
|
|
User: user,
|
|
Timestamp: time.Now().Unix(),
|
|
Payload: payload,
|
|
}
|
|
if dt != nil {
|
|
evt.DataType = int64(dt.EnumIndex())
|
|
} else {
|
|
evt.DataType = -1
|
|
}
|
|
|
|
body, _ := json.Marshal(evt)
|
|
sig, _ := priv.Sign(body)
|
|
evt.Signature = sig
|
|
return evt
|
|
}
|
|
|
|
func (e *Event) RawEvent() *Event {
|
|
return &Event{
|
|
Type: e.Type,
|
|
From: e.From,
|
|
User: e.User,
|
|
DataType: e.DataType,
|
|
Timestamp: e.Timestamp,
|
|
Payload: e.Payload,
|
|
}
|
|
}
|
|
|
|
func (e *Event) toRawByte() ([]byte, error) {
|
|
return json.Marshal(e.RawEvent())
|
|
}
|
|
|
|
func (event *Event) Verify(p *peer.Peer) error {
|
|
if p == nil {
|
|
return errors.New("no peer found")
|
|
}
|
|
if p.Relation == peer.BLACKLIST { // if peer is blacklisted... quit...
|
|
return errors.New("peer is blacklisted")
|
|
}
|
|
pubKey, err := PubKeyFromString(p.PublicKey) // extract pubkey from pubkey str
|
|
if err != nil {
|
|
return errors.New("pubkey is malformed")
|
|
}
|
|
data, err := event.toRawByte()
|
|
if err != nil {
|
|
return err
|
|
} // extract byte from raw event excluding signature.
|
|
if ok, _ := pubKey.Verify(data, event.Signature); !ok { // then verify if pubkey sign this message...
|
|
return errors.New("check signature failed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type TopicNodeActivityPub struct {
|
|
DID string
|
|
PeerID string
|
|
NodeActivity peer.PeerState
|
|
}
|
|
|
|
type LongLivedPubSubService struct {
|
|
Host host.Host
|
|
LongLivedPubSubs map[string]*pubsub.Topic
|
|
PubsubMu sync.RWMutex
|
|
}
|
|
|
|
func NewLongLivedPubSubService(h host.Host) *LongLivedPubSubService {
|
|
return &LongLivedPubSubService{
|
|
Host: h,
|
|
LongLivedPubSubs: map[string]*pubsub.Topic{},
|
|
}
|
|
}
|
|
|
|
func (s *LongLivedPubSubService) processEvent(
|
|
ctx context.Context,
|
|
p *peer.Peer,
|
|
event *Event,
|
|
topicName string, handler func(context.Context, string, *Event) error) error {
|
|
if err := event.Verify(p); err != nil {
|
|
return err
|
|
}
|
|
return handler(ctx, topicName, event)
|
|
}
|
|
|
|
const TopicPubSubNodeActivity = "oc-node-activity"
|
|
const TopicPubSubSearch = "oc-node-search"
|
|
|
|
func (s *LongLivedPubSubService) SubscribeToNodeActivity(ps *pubsub.PubSub) error {
|
|
ps.RegisterTopicValidator(TopicPubSubNodeActivity, func(ctx context.Context, p pp.ID, m *pubsub.Message) bool {
|
|
return true
|
|
})
|
|
if topic, err := ps.Join(TopicPubSubNodeActivity); err != nil {
|
|
return err
|
|
} else {
|
|
s.PubsubMu.Lock()
|
|
defer s.PubsubMu.Unlock()
|
|
s.LongLivedPubSubs[TopicPubSubNodeActivity] = topic
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *LongLivedPubSubService) SubscribeToSearch(ps *pubsub.PubSub) error {
|
|
ps.RegisterTopicValidator(TopicPubSubSearch, func(ctx context.Context, p pp.ID, m *pubsub.Message) bool {
|
|
return true
|
|
})
|
|
if topic, err := ps.Join(TopicPubSubSearch); err != nil {
|
|
return err
|
|
} else {
|
|
s.PubsubMu.Lock()
|
|
defer s.PubsubMu.Unlock()
|
|
s.LongLivedPubSubs[TopicPubSubSearch] = topic
|
|
}
|
|
return nil
|
|
}
|