FULL OC-DISCOVERY LOGIC
This commit is contained in:
42
daemons/node/pubsub/handler.go
Normal file
42
daemons/node/pubsub/handler.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"oc-discovery/daemons/node/common"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
func (ps *PubSubService) handleEvent(ctx context.Context, topicName string, evt *common.Event) error {
|
||||
action := ps.getTopicName(topicName)
|
||||
if err := ps.handleEventSearch(ctx, evt, action); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *PubSubService) handleEventSearch( // only : on partner followings. 3 canals for every partner.
|
||||
ctx context.Context,
|
||||
evt *common.Event,
|
||||
action tools.PubSubAction,
|
||||
) error {
|
||||
if !(action == tools.PB_SEARCH_RESPONSE || action == tools.PB_SEARCH) {
|
||||
return nil
|
||||
}
|
||||
// TODO VERIFY: FROM SHOULD BE A PEER ID OR A DID
|
||||
if p, err := ps.Node.GetPeerRecord(ctx, evt.From); err == nil {
|
||||
if err := evt.Verify(p); err != nil {
|
||||
return err
|
||||
}
|
||||
switch action {
|
||||
case tools.PB_SEARCH: // when someone ask for search.
|
||||
if err := ps.StreamService.SendResponse(p, evt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
82
daemons/node/pubsub/publish.go
Normal file
82
daemons/node/pubsub/publish.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"oc-discovery/daemons/node/common"
|
||||
"oc-discovery/models"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
func (ps *PubSubService) SearchPublishEvent(
|
||||
ctx context.Context, dt *tools.DataType, typ string, user string, search string) error {
|
||||
switch typ {
|
||||
case "known": // define Search Strategy
|
||||
return ps.StreamService.SearchKnownPublishEvent(dt, user, search) //if partners focus only them*/
|
||||
case "partner": // define Search Strategy
|
||||
return ps.StreamService.SearchPartnersPublishEvent(dt, user, search) //if partners focus only them*/
|
||||
case "all": // Gossip PubSub
|
||||
b, err := json.Marshal(map[string]string{"search": search})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ps.searchPublishEvent(ctx, dt, user, b)
|
||||
default:
|
||||
return errors.New("no type of research found")
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *PubSubService) searchPublishEvent(
|
||||
ctx context.Context, dt *tools.DataType, user string, payload []byte) error {
|
||||
id, err := oclib.GenerateNodeID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ps.subscribeEvents(ctx, dt, tools.PB_SEARCH_RESPONSE, id, 60); err != nil { // TODO Catpure Event !
|
||||
return err
|
||||
}
|
||||
return ps.publishEvent(ctx, dt, tools.PB_SEARCH, user, "", payload, false)
|
||||
}
|
||||
|
||||
func (ps *PubSubService) publishEvent(
|
||||
ctx context.Context, dt *tools.DataType, action tools.PubSubAction, user string,
|
||||
peerID string, payload []byte, chanNamedByDt bool,
|
||||
) error {
|
||||
name := action.String() + "#" + peerID
|
||||
if chanNamedByDt && dt != nil { // if a datatype is precised then : app.action.datatype#peerID
|
||||
name = action.String() + "." + (*dt).String() + "#" + peerID
|
||||
}
|
||||
|
||||
from, err := oclib.GenerateNodeID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
priv, err := common.LoadKeyFromFile(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, _ := json.Marshal(models.NewEvent(name, from, dt, user, payload, priv))
|
||||
topic, err := ps.PS.Join(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return topic.Publish(ctx, msg)
|
||||
}
|
||||
|
||||
func (pc *PubSubService) getDefaultFilter(search string) map[string][]dbs.Filter {
|
||||
return map[string][]dbs.Filter{ // filter by like name, short_description, description, owner, url if no filters are provided
|
||||
"abstractintanciatedresource.abstractresource.abstractobject.name": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
"abstractintanciatedresource.abstractresource.type": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
"abstractintanciatedresource.abstractresource.short_description": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
"abstractintanciatedresource.abstractresource.description": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
"abstractintanciatedresource.abstractresource.owners.name": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
"abstractintanciatedresource.abstractresource.abstractobject.creator_id": {{Operator: dbs.EQUAL.String(), Value: search}},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO REVIEW PUBLISHING + ADD SEARCH ON PUBLIC : YES
|
||||
// TODO : Search should verify DataType
|
||||
45
daemons/node/pubsub/service.go
Normal file
45
daemons/node/pubsub/service.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"oc-discovery/daemons/node/common"
|
||||
"oc-discovery/daemons/node/stream"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
)
|
||||
|
||||
type PubSubService struct {
|
||||
Node common.DiscoveryPeer
|
||||
Host host.Host
|
||||
PS *pubsub.PubSub
|
||||
StreamService *stream.StreamService
|
||||
Subscription []string
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func InitPubSub(ctx context.Context, h host.Host, ps *pubsub.PubSub, node common.DiscoveryPeer, streamService *stream.StreamService) (*PubSubService, error) {
|
||||
service := &PubSubService{
|
||||
Node: node,
|
||||
Host: h,
|
||||
StreamService: streamService,
|
||||
PS: ps,
|
||||
}
|
||||
|
||||
service.initSubscribeEvents(ctx)
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func (ps *PubSubService) getTopicName(topicName string) tools.PubSubAction {
|
||||
ns := strings.Split(topicName, ".")
|
||||
if len(ns) > 0 {
|
||||
return tools.GetActionString(ns[0])
|
||||
}
|
||||
return tools.NONE
|
||||
}
|
||||
|
||||
func (ix *PubSubService) Close() {
|
||||
}
|
||||
102
daemons/node/pubsub/subscribe.go
Normal file
102
daemons/node/pubsub/subscribe.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"oc-discovery/daemons/node/common"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/models/peer"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
)
|
||||
|
||||
func (ps *PubSubService) initSubscribeEvents(ctx context.Context) error {
|
||||
if err := ps.subscribeEvents(ctx, nil, tools.PB_SEARCH, "", -1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generic function to subscribe to DHT flow of event
|
||||
func (ps *PubSubService) subscribeEvents(
|
||||
ctx context.Context, dt *tools.DataType, action tools.PubSubAction, peerID string, timeout int,
|
||||
) error {
|
||||
// define a name app.action#peerID
|
||||
name := action.String() + "#" + peerID
|
||||
if dt != nil { // if a datatype is precised then : app.action.datatype#peerID
|
||||
name = action.String() + "." + (*dt).String() + "#" + peerID
|
||||
}
|
||||
topic, err := ps.PS.Join(name) // find out the topic
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sub, err := topic.Subscribe() // then subscribe to it
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps.mutex.Lock() // add safely in cache your subscription.
|
||||
ps.Subscription = append(ps.Subscription, name)
|
||||
ps.mutex.Unlock()
|
||||
|
||||
// launch loop waiting for results.
|
||||
go ps.waitResults(ctx, sub, name, timeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *PubSubService) waitResults(ctx context.Context, sub *pubsub.Subscription, topicName string, timeout int) {
|
||||
logger := oclib.GetLogger()
|
||||
defer ctx.Done()
|
||||
for {
|
||||
ps.mutex.Lock() // check safely if cache is actually notified subscribed to topic
|
||||
if !slices.Contains(ps.Subscription, topicName) { // if not kill the loop.
|
||||
break
|
||||
}
|
||||
ps.mutex.Unlock()
|
||||
// if still subscribed -> wait for new message
|
||||
var cancel context.CancelFunc
|
||||
if timeout != -1 {
|
||||
ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
}
|
||||
msg, err := sub.Next(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
// timeout hit, no message before deadline kill subsciption.
|
||||
ps.mutex.Lock()
|
||||
subs := []string{}
|
||||
for _, ss := range ps.Subscription {
|
||||
if ss != topicName {
|
||||
subs = append(subs, ss)
|
||||
}
|
||||
}
|
||||
ps.Subscription = subs
|
||||
ps.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
var evt common.Event
|
||||
if err := json.Unmarshal(msg.Data, &evt); err != nil { // map to event
|
||||
continue
|
||||
}
|
||||
if p, err := ps.Node.GetPeerRecord(ctx, evt.From); err == nil {
|
||||
if err := ps.processEvent(ctx, p, &evt, topicName); err != nil {
|
||||
logger.Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *PubSubService) processEvent(
|
||||
ctx context.Context, p *peer.Peer, event *common.Event, topicName string) error {
|
||||
if err := event.Verify(p); err != nil {
|
||||
return err
|
||||
}
|
||||
return ps.handleEvent(ctx, topicName, event)
|
||||
}
|
||||
Reference in New Issue
Block a user