decentralized -> peer discovery
This commit is contained in:
@@ -22,6 +22,7 @@ func (o *DistributedPeerController) Search() {
|
|||||||
//user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
//user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||||
// store and return Id or post with UUIDLibDataEnum
|
// store and return Id or post with UUIDLibDataEnum
|
||||||
search := o.Ctx.Input.Param(":search")
|
search := o.Ctx.Input.Param(":search")
|
||||||
|
|
||||||
service := infrastructure.GetDHTService()
|
service := infrastructure.GetDHTService()
|
||||||
code := 400
|
code := 400
|
||||||
err := "no DHT Service available"
|
err := "no DHT Service available"
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (o *PeerController) Link() {
|
|||||||
o.Data["json"] = map[string]interface{}{
|
o.Data["json"] = map[string]interface{}{
|
||||||
"data": nil,
|
"data": nil,
|
||||||
"code": 400,
|
"code": 400,
|
||||||
"error": "can't link relation to ourself",
|
"error": "can't link relation by ourself",
|
||||||
}
|
}
|
||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
return
|
return
|
||||||
@@ -82,7 +82,7 @@ func (o *PeerController) Link() {
|
|||||||
o.Data["json"] = map[string]interface{}{
|
o.Data["json"] = map[string]interface{}{
|
||||||
"data": nil,
|
"data": nil,
|
||||||
"code": 400,
|
"code": 400,
|
||||||
"error": "can't link relation",
|
"error": "can't link relation to an other peer",
|
||||||
}
|
}
|
||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
return
|
return
|
||||||
@@ -122,7 +122,7 @@ func (o *PeerController) Link() {
|
|||||||
func (o *PeerController) Unknown() {
|
func (o *PeerController) Unknown() {
|
||||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||||
id := o.Ctx.Input.Param(":id")
|
id := o.Ctx.Input.Param(":id")
|
||||||
req := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil)
|
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil)
|
||||||
data := req.LoadOne(id)
|
data := req.LoadOne(id)
|
||||||
o.changeRelation(data.ToPeer(), peer.NONE, req)
|
o.changeRelation(data.ToPeer(), peer.NONE, req)
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ func (o *PeerController) Unknown() {
|
|||||||
func (o *PeerController) Partner() {
|
func (o *PeerController) Partner() {
|
||||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||||
id := o.Ctx.Input.Param(":id")
|
id := o.Ctx.Input.Param(":id")
|
||||||
req := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil)
|
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil)
|
||||||
data := req.LoadOne(id)
|
data := req.LoadOne(id)
|
||||||
o.changeRelation(data.ToPeer(), peer.PARTNER, req)
|
o.changeRelation(data.ToPeer(), peer.PARTNER, req)
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,7 @@ func (o *PeerController) Blacklist() {
|
|||||||
id := o.Ctx.Input.Param(":id")
|
id := o.Ctx.Input.Param(":id")
|
||||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).UpdateOne(map[string]interface{}{
|
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).UpdateOne(map[string]interface{}{
|
||||||
"relation": peer.BLACKLIST,
|
"relation": peer.BLACKLIST,
|
||||||
|
"state": peer.OFFLINE,
|
||||||
}, id)
|
}, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,3 +219,20 @@ func (o *PeerController) DeleteState() {
|
|||||||
}, id)
|
}, id)
|
||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Un pair change le statut d'un autre pair, alors ce dernier est joins automatiquement, on ne peut pas s'auto lié seul un externe peut faire ce processus de demande.
|
||||||
|
On change le pair pour pouvoir le mettre à jour, alors, le lien se met à jour automatiquement. p1 -> update status -> link (p2) -> p2 response -> update status -> link (p1)
|
||||||
|
|
||||||
|
Que définit le partnership de type : Partner, Blacklist et None.
|
||||||
|
|
||||||
|
BlackList : implique qu'on ne peut pas "voir" un pair et ses ressources, d'un coté comme de l'autre. Il suffit qu'un pair définisse la Blacklist, le pair opposant ne peut plus le voir.
|
||||||
|
(DHT allons plus loin)
|
||||||
|
|
||||||
|
Partner : Donne accès à des ressources non publique duquel un partnership à été modélisé, de type * ou dédié.
|
||||||
|
|
||||||
|
None : Est visible, et ne donne accès qu'au ressources publique et aux profiles all. Les profiles dédiés ne s'appliquent que si on est dans une situation de partenariat.
|
||||||
|
|
||||||
|
|
||||||
|
Note: L'état PENDING revient à dire qu'une relation est à l'état None,... si il y a une vérification on considère tout status à None. C'est une vérification importante.
|
||||||
|
*/
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.24.6
|
|||||||
toolchain go1.24.11
|
toolchain go1.24.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260126093615-bc94f2b188e6
|
||||||
github.com/beego/beego/v2 v2.3.8
|
github.com/beego/beego/v2 v2.3.8
|
||||||
github.com/smartystreets/goconvey v1.7.2
|
github.com/smartystreets/goconvey v1.7.2
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -16,6 +16,8 @@ cloud.o-forge.io/core/oc-lib v0.0.0-20260123064804-d06c9e933783 h1:ztJplXt5FIrST
|
|||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260123064804-d06c9e933783/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260123064804-d06c9e933783/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1 h1:K7ind/dAshdoFb0om35YY6phWJcYhHj1YMlTrrwKH4s=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1 h1:K7ind/dAshdoFb0om35YY6phWJcYhHj1YMlTrrwKH4s=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260126093615-bc94f2b188e6 h1:Sxjq1lQwSl+gkUYag4wAb6j74uU/JZviw1hkFavt58o=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20260126093615-bc94f2b188e6/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/beego/beego/v2 v2.3.8 h1:wplhB1pF4TxR+2SS4PUej8eDoH4xGfxuHfS7wAk9VBc=
|
github.com/beego/beego/v2 v2.3.8 h1:wplhB1pF4TxR+2SS4PUej8eDoH4xGfxuHfS7wAk9VBc=
|
||||||
github.com/beego/beego/v2 v2.3.8/go.mod h1:8vl9+RrXqvodrl9C8yivX1e6le6deCK6RWeq8R7gTTg=
|
github.com/beego/beego/v2 v2.3.8/go.mod h1:8vl9+RrXqvodrl9C8yivX1e6le6deCK6RWeq8R7gTTg=
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func verify(pub crypto.PubKey, data, sig []byte) (bool, error) {
|
|||||||
return pub.Verify(data, sig)
|
return pub.Verify(data, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadKeyFromFile(isPublic bool) (crypto.PrivKey, error) {
|
func LoadKeyFromFile(isPublic bool) (crypto.PrivKey, error) {
|
||||||
path := conf.GetConfig().PrivateKeyPath
|
path := conf.GetConfig().PrivateKeyPath
|
||||||
if isPublic {
|
if isPublic {
|
||||||
path = conf.GetConfig().PublicKeyPath
|
path = conf.GetConfig().PublicKeyPath
|
||||||
@@ -35,12 +35,12 @@ func loadKeyFromFile(isPublic bool) (crypto.PrivKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func VerifyPubWithPriv() bool {
|
func VerifyPubWithPriv() bool {
|
||||||
priv, err := loadKeyFromFile(false)
|
priv, err := LoadKeyFromFile(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
pub, err := loadKeyFromFile(true)
|
pub, err := LoadKeyFromFile(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"oc-peer/conf"
|
"oc-peer/conf"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/peer"
|
pp "cloud.o-forge.io/core/oc-lib/models/peer"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -21,20 +22,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DHTRecord struct {
|
type DHTRecord struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
State int
|
State int `json:"state"`
|
||||||
PeerID string
|
DID string `json:"did"`
|
||||||
PubKey []byte
|
PeerID string `json:"peer_id"`
|
||||||
URL string
|
PubKey []byte `json:"pub_key"`
|
||||||
NATSUrl string
|
URL string `json:"url"`
|
||||||
Signature []byte
|
NATSUrl string `json:"nats_url"`
|
||||||
ExpiryDate time.Time
|
Wallet string `json:"wallet"`
|
||||||
|
Signature []byte `json:"signature"`
|
||||||
|
ExpiryDate time.Time `json:"expiry_date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DHTService struct {
|
type DHTService struct {
|
||||||
Key string
|
Key string
|
||||||
Host host.Host
|
Host host.Host
|
||||||
DHT *dht.IpfsDHT
|
DHT *dht.IpfsDHT
|
||||||
|
Cache []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var singletonService *DHTService
|
var singletonService *DHTService
|
||||||
@@ -45,7 +49,7 @@ func GetDHTService() *DHTService {
|
|||||||
|
|
||||||
func Init(ctx context.Context) (*DHTService, error) {
|
func Init(ctx context.Context) (*DHTService, error) {
|
||||||
service := &DHTService{}
|
service := &DHTService{}
|
||||||
priv, err := loadKeyFromFile(false)
|
priv, err := LoadKeyFromFile(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -63,21 +67,115 @@ func Init(ctx context.Context) (*DHTService, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
err = service.DHT.Bootstrap(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
singletonService = service
|
singletonService = service
|
||||||
if VerifyPubWithPriv() {
|
if VerifyPubWithPriv() {
|
||||||
if _, err := singletonService.ClaimName(context.Background(),
|
if _, err := singletonService.ClaimName(context.Background(),
|
||||||
conf.GetConfig().Name,
|
conf.GetConfig().Name,
|
||||||
conf.GetConfig().Hostname); err == nil {
|
conf.GetConfig().Hostname); err == nil {
|
||||||
go func() {
|
go service.RefreshKeys(ctx, 30*time.Minute)
|
||||||
for {
|
|
||||||
singletonService.RefreshName(context.Background())
|
|
||||||
time.Sleep(59 * time.Minute)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return service, service.DHT.Bootstrap(ctx)
|
return service, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DHTService) RefreshKeys(ctx context.Context, interval time.Duration) {
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
go func() {
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
s := []string{}
|
||||||
|
s = append(s, d.Cache...)
|
||||||
|
for _, key := range s {
|
||||||
|
_, _ = d.GetValue(ctx, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DHTService) PutValue(
|
||||||
|
ctx context.Context,
|
||||||
|
key string,
|
||||||
|
value []byte,
|
||||||
|
) error {
|
||||||
|
err := d.DHT.PutValue(ctx, key, value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !slices.Contains(d.Cache, key) {
|
||||||
|
d.Cache = append(d.Cache, key)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DHTService) GetValue(
|
||||||
|
ctx context.Context,
|
||||||
|
key string,
|
||||||
|
) (*DHTRecord, error) {
|
||||||
|
dht, err := d.DHT.GetValue(ctx, key)
|
||||||
|
if err != nil {
|
||||||
|
cache := []string{}
|
||||||
|
for _, c := range d.Cache {
|
||||||
|
if c != key {
|
||||||
|
cache = append(cache, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.Cache = cache
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !slices.Contains(d.Cache, key) {
|
||||||
|
d.Cache = append(d.Cache, key)
|
||||||
|
}
|
||||||
|
var data *DHTRecord
|
||||||
|
json.Unmarshal(dht, data)
|
||||||
|
|
||||||
|
if data == nil {
|
||||||
|
return nil, errors.New("no record found")
|
||||||
|
}
|
||||||
|
|
||||||
|
access := pp.NewAccessor(&tools.APIRequest{Admin: true})
|
||||||
|
p := &pp.Peer{
|
||||||
|
AbstractObject: utils.AbstractObject{
|
||||||
|
UUID: uuid.New().String(),
|
||||||
|
Name: data.Name,
|
||||||
|
},
|
||||||
|
State: pp.ONLINE,
|
||||||
|
Relation: pp.SELF,
|
||||||
|
PeerID: d.Host.ID().String(),
|
||||||
|
PublicKey: string(data.PubKey),
|
||||||
|
Url: data.URL,
|
||||||
|
NATSUrl: oclib.GetConfig().NATSUrl,
|
||||||
|
WalletAddress: data.Wallet,
|
||||||
|
}
|
||||||
|
if founded, _, err := access.Search(nil, fmt.Sprintf("%v", pp.SELF.EnumIndex()), false); err != nil || len(founded) == 0 {
|
||||||
|
access.StoreOne(p)
|
||||||
|
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil && f.(*pp.Peer).Relation != pp.BLACKLIST {
|
||||||
|
f.(*pp.Peer).State = pp.ONLINE
|
||||||
|
f.(*pp.Peer).NATSUrl = p.NATSUrl
|
||||||
|
f.(*pp.Peer).Url = p.Url
|
||||||
|
f.(*pp.Peer).PeerID = p.PeerID
|
||||||
|
f.(*pp.Peer).Relation = p.Relation
|
||||||
|
f.(*pp.Peer).WalletAddress = p.WalletAddress
|
||||||
|
access.UpdateOne(f, f.GetID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DHTService) generateKey(
|
||||||
|
sub string,
|
||||||
|
name string,
|
||||||
|
) string {
|
||||||
|
return "/opencloud/" + sub + "/" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create your peer.
|
// Create your peer.
|
||||||
@@ -85,7 +183,7 @@ func (d *DHTService) ClaimName(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
name string,
|
name string,
|
||||||
endPoint string,
|
endPoint string,
|
||||||
) (*peer.Peer, error) {
|
) (*pp.Peer, error) {
|
||||||
if endPoint == "" {
|
if endPoint == "" {
|
||||||
return nil, errors.New("no endpoint found for peer" + name)
|
return nil, errors.New("no endpoint found for peer" + name)
|
||||||
}
|
}
|
||||||
@@ -107,67 +205,62 @@ func (d *DHTService) ClaimName(
|
|||||||
|
|
||||||
rec.URL = endPoint
|
rec.URL = endPoint
|
||||||
rec.NATSUrl = oclib.GetConfig().NATSUrl
|
rec.NATSUrl = oclib.GetConfig().NATSUrl
|
||||||
rec.State = peer.ONLINE.EnumIndex()
|
rec.State = pp.ONLINE.EnumIndex()
|
||||||
rec.ExpiryDate = expiry
|
rec.ExpiryDate = expiry
|
||||||
|
|
||||||
data, _ := json.Marshal(rec)
|
data, _ := json.Marshal(rec)
|
||||||
|
|
||||||
key := name
|
key := d.generateKey("peer", rec.Name)
|
||||||
|
|
||||||
// retrieve your key name in standard
|
// retrieve your key name in standard
|
||||||
existing, err := d.DHT.GetValue(ctx, key)
|
old, err := d.GetValue(ctx, key)
|
||||||
if err == nil && existing != nil {
|
if err == nil {
|
||||||
var old DHTRecord
|
|
||||||
_ = json.Unmarshal(existing, &old)
|
|
||||||
|
|
||||||
if old.PeerID != d.Host.ID().String() { // check if someone claims your name before
|
if old.PeerID != d.Host.ID().String() { // check if someone claims your name before
|
||||||
return nil, errors.New("name already claimed by another peer")
|
return nil, errors.New("name already claimed by another peer")
|
||||||
|
// TODO : can be fragile if 2 peers connect at the same time
|
||||||
}
|
}
|
||||||
if now.After(old.ExpiryDate) {
|
if now.After(old.ExpiryDate) {
|
||||||
payload, _ := json.Marshal(rec)
|
payload, _ := json.Marshal(rec)
|
||||||
d.DHT.PutValue(ctx, key, payload)
|
d.PutValue(ctx, key, payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.DHT.PutValue(ctx, key, data); err != nil {
|
if err := d.PutValue(ctx, key, data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pubStr := base64.StdEncoding.EncodeToString(pubBytes)
|
pubStr := base64.StdEncoding.EncodeToString(pubBytes)
|
||||||
d.Key = key
|
d.Key = key
|
||||||
access := peer.NewAccessor(&tools.APIRequest{Admin: true})
|
access := pp.NewAccessor(&tools.APIRequest{Admin: true})
|
||||||
p := &peer.Peer{
|
p := &pp.Peer{
|
||||||
AbstractObject: utils.AbstractObject{
|
AbstractObject: utils.AbstractObject{
|
||||||
UUID: uuid.New().String(),
|
UUID: uuid.New().String(),
|
||||||
Name: name,
|
Name: name,
|
||||||
},
|
},
|
||||||
State: peer.ONLINE,
|
State: pp.ONLINE,
|
||||||
Relation: peer.SELF,
|
Relation: pp.SELF,
|
||||||
PeerID: d.Host.ID().String(),
|
PeerID: d.Host.ID().String(),
|
||||||
PublicKey: pubStr,
|
PublicKey: pubStr,
|
||||||
Url: endPoint,
|
Url: endPoint,
|
||||||
NATSUrl: oclib.GetConfig().NATSUrl,
|
NATSUrl: oclib.GetConfig().NATSUrl,
|
||||||
WalletAddress: "my-wallet",
|
WalletAddress: "my-wallet",
|
||||||
}
|
}
|
||||||
if founded, _, err := access.Search(nil, fmt.Sprintf("%v", peer.SELF.EnumIndex()), false); err != nil || len(founded) == 0 {
|
if founded, _, err := access.Search(nil, fmt.Sprintf("%v", pp.SELF.EnumIndex()), false); err != nil || len(founded) == 0 {
|
||||||
access.StoreOne(p)
|
access.StoreOne(p)
|
||||||
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil {
|
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil {
|
||||||
f.(*peer.Peer).Name = name
|
f.(*pp.Peer).Name = name
|
||||||
f.(*peer.Peer).PeerID = d.Host.ID().String()
|
f.(*pp.Peer).PeerID = d.Host.ID().String()
|
||||||
f.(*peer.Peer).State = peer.ONLINE
|
f.(*pp.Peer).State = pp.ONLINE
|
||||||
f.(*peer.Peer).Url = endPoint
|
f.(*pp.Peer).Url = endPoint
|
||||||
|
f.(*pp.Peer).NATSUrl = oclib.GetConfig().NATSUrl
|
||||||
|
f.(*pp.Peer).Relation = pp.SELF
|
||||||
access.UpdateOne(f, f.GetID())
|
access.UpdateOne(f, f.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DHTService) treatPeer(ctx context.Context, key string, data []byte) (*peer.Peer, error) {
|
func (d *DHTService) treatPeer(ctx context.Context, key string, rec *DHTRecord) (*pp.Peer, error) {
|
||||||
var rec DHTRecord
|
|
||||||
if err := json.Unmarshal(data, &rec); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey, err := crypto.UnmarshalPublicKey(rec.PubKey)
|
pubKey, err := crypto.UnmarshalPublicKey(rec.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -187,107 +280,105 @@ func (d *DHTService) treatPeer(ctx context.Context, key string, data []byte) (*p
|
|||||||
pubBytes, _ := pubKey.Raw()
|
pubBytes, _ := pubKey.Raw()
|
||||||
pubStr := base64.StdEncoding.EncodeToString(pubBytes)
|
pubStr := base64.StdEncoding.EncodeToString(pubBytes)
|
||||||
|
|
||||||
rel := peer.NONE
|
rel := pp.NONE
|
||||||
if d.Key == key {
|
if d.Key == key {
|
||||||
rel = peer.SELF
|
rel = pp.SELF
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &peer.Peer{
|
p := &pp.Peer{
|
||||||
AbstractObject: utils.AbstractObject{
|
AbstractObject: utils.AbstractObject{
|
||||||
UUID: uuid.New().String(),
|
UUID: uuid.New().String(),
|
||||||
Name: rec.Name,
|
Name: rec.Name,
|
||||||
},
|
},
|
||||||
State: peer.ONLINE,
|
State: pp.ONLINE,
|
||||||
Relation: rel,
|
Relation: rel,
|
||||||
PeerID: rec.PeerID,
|
PeerID: rec.PeerID,
|
||||||
PublicKey: pubStr,
|
PublicKey: pubStr,
|
||||||
Url: rec.URL,
|
Url: rec.URL,
|
||||||
NATSUrl: rec.NATSUrl,
|
NATSUrl: rec.NATSUrl,
|
||||||
|
WalletAddress: rec.Wallet,
|
||||||
}
|
}
|
||||||
access := peer.NewAccessor(&tools.APIRequest{Admin: true})
|
access := pp.NewAccessor(&tools.APIRequest{Admin: true})
|
||||||
if now.After(rec.ExpiryDate) {
|
if now.After(rec.ExpiryDate) {
|
||||||
rec.State = peer.OFFLINE.EnumIndex()
|
rec.State = pp.OFFLINE.EnumIndex()
|
||||||
p.State = peer.OFFLINE
|
p.State = pp.OFFLINE
|
||||||
payload, _ := json.Marshal(rec)
|
payload, _ := json.Marshal(rec)
|
||||||
d.DHT.PutValue(ctx, key, payload)
|
d.PutValue(ctx, key, payload)
|
||||||
if founded, _, err := access.Search(nil, p.Name, false); err != nil || len(founded) == 0 {
|
if founded, _, err := access.Search(nil, p.Name, false); err != nil || len(founded) == 0 {
|
||||||
access.StoreOne(p)
|
access.StoreOne(p)
|
||||||
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil {
|
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil {
|
||||||
f.(*peer.Peer).State = peer.OFFLINE
|
f.(*pp.Peer).State = pp.OFFLINE
|
||||||
access.UpdateOne(f, f.GetID())
|
access.UpdateOne(f, f.GetID())
|
||||||
}
|
}
|
||||||
return nil, errors.New("peer " + key + " is expired")
|
return nil, errors.New("peer " + key + " is expired")
|
||||||
}
|
}
|
||||||
if rec.State == peer.OFFLINE.EnumIndex() {
|
if rec.State == pp.OFFLINE.EnumIndex() {
|
||||||
if founded, _, err := access.Search(nil, p.Name, false); err != nil || len(founded) == 0 {
|
if founded, _, err := access.Search(nil, p.Name, false); err != nil || len(founded) == 0 {
|
||||||
pp, _, err := access.StoreOne(p)
|
ppp, _, err := access.StoreOne(p)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return pp.(*peer.Peer), nil
|
return ppp.(*pp.Peer), nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f, ok := peer.CheckPeerStatus(founded[0].GetID(), "")
|
f, ok := pp.CheckPeerStatus(founded[0].GetID(), "")
|
||||||
if ok {
|
if ok {
|
||||||
f.State = peer.ONLINE
|
f.State = pp.ONLINE
|
||||||
} else {
|
} else {
|
||||||
f.State = peer.OFFLINE
|
f.State = pp.OFFLINE
|
||||||
}
|
}
|
||||||
pp, _, err := access.UpdateOne(f, f.GetID())
|
ppp, _, err := access.UpdateOne(f, f.GetID())
|
||||||
if err == nil && ok {
|
if err == nil && ok {
|
||||||
return pp.(*peer.Peer), nil
|
return ppp.(*pp.Peer), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New("peer " + key + " is offline")
|
return nil, errors.New("peer " + key + " is offline")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DHTService) GetPeer(
|
|
||||||
ctx context.Context,
|
|
||||||
name string,
|
|
||||||
) (*peer.Peer, error) {
|
|
||||||
key := name
|
|
||||||
data, err := d.DHT.GetValue(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("no DHT peer not found")
|
|
||||||
}
|
|
||||||
return d.treatPeer(ctx, key, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discover a specific Peer
|
// Discover a specific Peer
|
||||||
func (d *DHTService) DiscoverPeers(
|
func (d *DHTService) DiscoverPeers(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
name string,
|
name string,
|
||||||
) ([]*peer.Peer, error) {
|
) ([]*pp.Peer, error) {
|
||||||
peers := []*peer.Peer{}
|
peers := []*pp.Peer{}
|
||||||
key := name
|
key := d.generateKey("peer", name)
|
||||||
datas, err := d.DHT.SearchValue(ctx, key)
|
datas, err := d.DHT.SearchValue(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("no DHT peer not found")
|
return nil, errors.New("no DHT peer not found")
|
||||||
}
|
}
|
||||||
for data := range datas {
|
for data := range datas {
|
||||||
if p, err := d.treatPeer(ctx, key, data); err == nil {
|
var dht *DHTRecord
|
||||||
|
json.Unmarshal(data, dht)
|
||||||
|
if p, err := d.treatPeer(ctx, key, dht); err == nil {
|
||||||
peers = append(peers, p)
|
peers = append(peers, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return peers, nil
|
return peers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DHTService) GetPeer(
|
||||||
|
ctx context.Context,
|
||||||
|
name string,
|
||||||
|
) (*pp.Peer, error) {
|
||||||
|
key := d.generateKey("peer", name)
|
||||||
|
data, err := d.GetValue(ctx, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("no DHT peer not found")
|
||||||
|
}
|
||||||
|
return d.treatPeer(ctx, key, data)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DHTService) existsDHT(ctx context.Context) (*DHTRecord, error) {
|
func (d *DHTService) existsDHT(ctx context.Context) (*DHTRecord, error) {
|
||||||
if d.Key == "" {
|
if d.Key == "" {
|
||||||
return nil, errors.New("no self peer found")
|
return nil, errors.New("no self peer found")
|
||||||
}
|
}
|
||||||
data, err := d.DHT.GetValue(ctx, d.Key)
|
rec, err := d.GetValue(ctx, d.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("no DHT peer found")
|
return nil, errors.New("no DHT peer found")
|
||||||
}
|
}
|
||||||
|
|
||||||
var rec DHTRecord
|
|
||||||
if err := json.Unmarshal(data, &rec); err != nil {
|
|
||||||
return &rec, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey, err := crypto.UnmarshalPublicKey(rec.PubKey)
|
pubKey, err := crypto.UnmarshalPublicKey(rec.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &rec, err
|
return rec, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dht := DHTRecord{
|
dht := DHTRecord{
|
||||||
@@ -298,42 +389,11 @@ func (d *DHTService) existsDHT(ctx context.Context) (*DHTRecord, error) {
|
|||||||
payload, _ := json.Marshal(dht)
|
payload, _ := json.Marshal(dht)
|
||||||
|
|
||||||
if ok, _ := verify(pubKey, payload, rec.Signature); !ok {
|
if ok, _ := verify(pubKey, payload, rec.Signature); !ok {
|
||||||
return &rec, err
|
return rec, err
|
||||||
}
|
}
|
||||||
return &rec, nil
|
return rec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DHTService) RefreshName( // peer should regulary refresh your host to not be settings up offline.
|
/*
|
||||||
ctx context.Context,
|
Apply Name interlude...
|
||||||
) error {
|
*/
|
||||||
rec, err := d.existsDHT(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
now := time.Now()
|
|
||||||
expiry := now.Add(1 * time.Hour)
|
|
||||||
rec.State = peer.ONLINE.EnumIndex()
|
|
||||||
rec.ExpiryDate = expiry
|
|
||||||
payload, _ := json.Marshal(rec)
|
|
||||||
d.DHT.PutValue(ctx, d.Key, payload)
|
|
||||||
access := peer.NewAccessor(&tools.APIRequest{Admin: true})
|
|
||||||
p := &peer.Peer{
|
|
||||||
AbstractObject: utils.AbstractObject{
|
|
||||||
UUID: uuid.New().String(),
|
|
||||||
Name: rec.Name,
|
|
||||||
},
|
|
||||||
State: peer.ONLINE, // online
|
|
||||||
Relation: peer.SELF, // self
|
|
||||||
PeerID: rec.PeerID,
|
|
||||||
PublicKey: string(rec.PubKey),
|
|
||||||
Url: rec.URL,
|
|
||||||
NATSUrl: rec.NATSUrl,
|
|
||||||
}
|
|
||||||
if founded, _, err := access.Search(nil, rec.Name, false); err != nil || len(founded) == 0 {
|
|
||||||
access.StoreOne(p)
|
|
||||||
} else if f, _, err := access.LoadOne(founded[0].GetID()); err == nil {
|
|
||||||
f.(*peer.Peer).State = peer.ONLINE
|
|
||||||
access.UpdateOne(f, f.GetID())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user