FULL OC-DISCOVERY LOGIC

This commit is contained in:
mr
2026-01-30 16:57:36 +01:00
parent d50e5d56f7
commit 562d86125e
24 changed files with 1769 additions and 929 deletions

View 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
}

View 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

View 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() {
}

View 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)
}