Files
indra/pkg/engine/peerstore.go

210 lines
5.6 KiB
Go

package engine
import (
"context"
"errors"
"fmt"
"github.com/indra-labs/indra/pkg/ad"
"github.com/indra-labs/indra/pkg/onions/adload"
"github.com/indra-labs/indra/pkg/util/slice"
"github.com/libp2p/go-libp2p/core/peer"
"reflect"
"github.com/indra-labs/indra/pkg/onions/adaddress"
"github.com/indra-labs/indra/pkg/onions/adintro"
"github.com/indra-labs/indra/pkg/onions/adpeer"
"github.com/indra-labs/indra/pkg/onions/adservices"
"github.com/indra-labs/indra/pkg/onions/reg"
"github.com/indra-labs/indra/pkg/util/splice"
pubsub "github.com/libp2p/go-libp2p-pubsub"
)
func (ng *Engine) SendAd(a slice.Bytes) (e error) {
return ng.topic.Publish(ng.ctx, a)
}
func (ng *Engine) RunAdHandler(handler func(p *pubsub.Message,
ctx context.Context) (e error)) {
// Since the frequency of updates should be around 1 hour we run here only
// one thread here. Relays indicate their loading as part of the response
// message protocol for ranking in the session cache.
go func(ng *Engine) {
out:
for {
var m *pubsub.Message
var e error
if m, e = ng.sub.Next(ng.ctx); e != nil {
continue
}
log.D.Ln("received message from gossip network")
if e = handler(m, ng.ctx); fails(e) {
continue
}
select {
case <-ng.ctx.Done():
log.D.Ln("shutting down ad handler")
break out
default:
}
}
return
}(ng)
}
const ErrWrongTypeDecode = "magic '%s' but type is '%s'"
func (ng *Engine) HandleAd(p *pubsub.Message, ctx context.Context) (e error) {
if len(p.Data) < 1 {
log.E.Ln("received slice of no length")
return
}
s := splice.NewFrom(p.Data)
c := reg.Recognise(s)
if c == nil {
return errors.New("ad not recognised")
}
if e = c.Decode(s); fails(e) {
return
}
var ok bool
switch c.(type) {
case *adaddress.Ad:
log.D.Ln("received", reflect.TypeOf(c), "from gossip network")
var addr *adaddress.Ad
if addr, ok = c.(*adaddress.Ad); !ok {
return fmt.Errorf(ErrWrongTypeDecode,
adaddress.Magic, reflect.TypeOf(c).String())
} else if !addr.Validate() {
return errors.New("addr ad failed validation")
}
// If we got to here now we can add to the PeerStore.
log.D.S("new ad for address:", c)
var id peer.ID
if id, e = peer.IDFromPublicKey(addr.Key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, adaddress.Magic, s.GetAll().ToBytes()); fails(e) {
return
}
case *adintro.Ad:
log.D.Ln("received", reflect.TypeOf(c), "from gossip network")
var intr *adintro.Ad
if intr, ok = c.(*adintro.Ad); !ok {
return fmt.Errorf(ErrWrongTypeDecode,
adintro.Magic, reflect.TypeOf(c).String())
} else if !intr.Validate() {
return errors.New("intro ad failed validation")
}
// If we got to here now we can add to the PeerStore.
log.D.S("new ad for intro:", c)
var id peer.ID
if id, e = peer.IDFromPublicKey(intr.Key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, adintro.Magic, s.GetAll().ToBytes()); fails(e) {
return
}
case *adload.Ad:
log.D.Ln("received", reflect.TypeOf(c), "from gossip network")
var lod *adload.Ad
if lod, ok = c.(*adload.Ad); !ok {
return fmt.Errorf(ErrWrongTypeDecode,
adaddress.Magic, reflect.TypeOf(c).String())
} else if !lod.Validate() {
return errors.New("load ad failed validation")
}
// If we got to here now we can add to the PeerStore.
log.D.S("new ad for load:", c)
var id peer.ID
if id, e = peer.IDFromPublicKey(lod.Key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, adservices.Magic, s.GetAll().ToBytes()); fails(e) {
return
}
case *adpeer.Ad:
log.D.Ln("received", reflect.TypeOf(c), "from gossip network")
var pa *adpeer.Ad
if pa, ok = c.(*adpeer.Ad); !ok {
return fmt.Errorf(ErrWrongTypeDecode,
adpeer.Magic, reflect.TypeOf(c).String())
} else if !pa.Validate() {
return errors.New("peer ad failed validation")
}
// If we got to here now we can add to the PeerStore.
log.D.S("new ad for peer:", c)
var id peer.ID
if id, e = peer.IDFromPublicKey(pa.Key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, adpeer.Magic, s.GetAll().ToBytes()); fails(e) {
return
}
case *adservices.Ad:
log.D.Ln("received", reflect.TypeOf(c), "from gossip network")
var sa *adservices.Ad
if sa, ok = c.(*adservices.Ad); !ok {
return fmt.Errorf(ErrWrongTypeDecode,
adservices.Magic, reflect.TypeOf(c).String())
} else if !sa.Validate() {
return errors.New("services ad failed validation")
}
// If we got to here now we can add to the PeerStore.
log.D.S("new ad for services:", c)
var id peer.ID
if id, e = peer.IDFromPublicKey(sa.Key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, adservices.Magic, s.GetAll().ToBytes()); fails(e) {
return
}
}
return
}
func (ng *Engine) GetPeerRecord(id peer.ID, key string) (add ad.Ad, e error) {
var a interface{}
if a, e = ng.Listener.Host.Peerstore().Get(id, key); fails(e) {
return
}
var ok bool
var adb slice.Bytes
if adb, ok = a.(slice.Bytes); !ok {
e = errors.New("peer record did not decode slice.Bytes")
return
}
if len(adb) < 1 {
e = fmt.Errorf("record for peer ID %v key %s has expired", id, key)
}
s := splice.NewFrom(adb)
c := reg.Recognise(s)
if c == nil {
e = errors.New(key + " peer record not recognised")
return
}
if e = c.Decode(s); fails(e) {
return
}
if add, ok = c.(ad.Ad); !ok {
e = errors.New(key + " peer record did not decode as Ad")
}
return
}
func (ng *Engine) ClearPeerRecord(id peer.ID, key string) (e error) {
if _, e = ng.Listener.Host.Peerstore().Get(id, key); fails(e) {
return
}
if e = ng.Listener.Host.
Peerstore().Put(id, key, []byte{}); fails(e) {
return
}
return
}