From 9e4d31e7974bcdcdedd30c382d12adf75bbe910d Mon Sep 17 00:00:00 2001 From: mr Date: Fri, 23 Jan 2026 08:07:17 +0100 Subject: [PATCH] add partnershipping mechanism --- conf/config.go | 2 + controllers/peer.go | 168 ++++++++++++++++++++++++++++++++++-------- go.mod | 2 +- go.sum | 12 +++ infrastructure/dht.go | 29 ++++---- main.go | 2 + 6 files changed, 171 insertions(+), 44 deletions(-) diff --git a/conf/config.go b/conf/config.go index 921e0e8..38c48e4 100644 --- a/conf/config.go +++ b/conf/config.go @@ -3,6 +3,8 @@ package conf import "sync" type Config struct { + Name string + Hostname string PublicKeyPath string PrivateKeyPath string DHTEndpointPort int64 diff --git a/controllers/peer.go b/controllers/peer.go index d699ef5..884cf7f 100644 --- a/controllers/peer.go +++ b/controllers/peer.go @@ -1,10 +1,10 @@ package controllers import ( - "encoding/json" - oclib "cloud.o-forge.io/core/oc-lib" + "cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/models/peer" + "cloud.o-forge.io/core/oc-lib/tools" beego "github.com/beego/beego/v2/server/web" ) @@ -28,23 +28,6 @@ func (o *PeerController) Search() { o.ServeJSON() } -// @Title Update -// @Description create peers -// @Param id path string true "the peer id you want to get" -// @Param body body models.peer true "The peer content" -// @Success 200 {object} models.peer -// @router /:id [put] -func (o *PeerController) Put() { - // store and return Id or post with UUID - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - id := o.Ctx.Input.Param(":id") - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).UpdateOne(res, id) - o.Data["json"] = data - o.ServeJSON() -} - // @Title GetAll // @Description find all peer // @Param is_draft query string false @@ -53,7 +36,16 @@ func (o *PeerController) Put() { func (o *PeerController) GetAll() { user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).LoadAll(isDraft == "true") + verify := o.Ctx.Input.Query("verify") + if verify == "true" { + o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(&dbs.Filters{ + And: map[string][]dbs.Filter{ + "verify": {{Operator: dbs.EQUAL.String(), Value: true}}, + }, + }, "", false) + } else { + o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).LoadAll(isDraft == "true") + } o.ServeJSON() } @@ -69,18 +61,83 @@ func (o *PeerController) Get() { o.ServeJSON() } -// @Title Partner -// @Description add partner peer by peerid -// @Param id path string true "the peer id you want to partner" +// @Title Link +// @Description find peer by peerid +// @Param id path string true "the peer id you want to get" // @Success 200 {peer} models.peer -// @router /:id/partner [post] -func (o *PeerController) Nano() { +// @router /:from/link/:relation [get] +func (o *PeerController) Link() { + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + id := o.Ctx.Input.Param(":from") + if ok, _ := peer.IsMySelf(peerID); ok { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "can't link relation to ourself", + } + o.ServeJSON() + return + } + if ok, _ := peer.IsMySelf(id); !ok { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "can't link relation", + } + o.ServeJSON() + return + } + relation := o.Ctx.Input.Param(":relation") // as partner, blacklist, unknown + req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil) + l := req.LoadOne(id) + if p := l.ToPeer(); p != nil { + if peer.GetRelationPath(relation) != -1 { + o.Data["json"] = req.UpdateOne(map[string]interface{}{ + "relation": peer.GetRelationPath(relation), + "verify": !(p.Relation == peer.PENDING_PARTNER || relation == peer.NONE.Path()), + }, p.GetID()) + return + } + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "relation unavailable", + } + o.ServeJSON() + return + } + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 404, + "error": "peer not found", + } + o.ServeJSON() +} + +// @Title unknown +// @Description add unknown peer by peerid +// @Param id path string true "the peer id you want to blacklist" +// @Success 200 {peer} models.peer +// @router /:id/unknown [post] +func (o *PeerController) Unknown() { user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).UpdateOne(map[string]interface{}{ - "state": peer.PARTNER, - }, id) - o.ServeJSON() + req := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil) + data := req.LoadOne(id) + o.changeRelation(data.ToPeer(), peer.NONE, req) +} + +// @Title Partner +// @Description add partner peer by peerid +// @Param id path string true "the peer id you want to blacklist" +// @Success 200 {peer} models.peer +// @router /:id/partner [post] +func (o *PeerController) Partner() { + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + id := o.Ctx.Input.Param(":id") + req := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil) + data := req.LoadOne(id) + o.changeRelation(data.ToPeer(), peer.PARTNER, req) } // @Title Blacklist @@ -92,8 +149,59 @@ func (o *PeerController) Blacklist() { user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) id := o.Ctx.Input.Param(":id") o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).UpdateOne(map[string]interface{}{ - "state": peer.BLACKLIST, + "relation": peer.BLACKLIST, }, id) +} + +// used from : peer ask, or response, only from peer origin is authorized to change... +func (o *PeerController) changeRelation(dest *peer.Peer, relation peer.PeerRelation, request *oclib.Request) { + if ok, _ := peer.IsMySelf(request.PeerID); !ok { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "can't change relation", + } + o.ServeJSON() + return + } + if ok, _ := peer.IsMySelf(dest.GetID()); ok { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "can't change ourself", + } + o.ServeJSON() + return + } + // store and return Id or post with UUID + if dest != nil { + if !dest.Verify && relation == peer.PARTNER { + relation = peer.PENDING_PARTNER + if _, err := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{}).CallGet(dest.Url, "/"+request.PeerID+"/link/"+relation.Path()); err != nil { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": err.Error(), + } + o.ServeJSON() + } + } + if dest.Verify && relation == peer.PENDING_PARTNER { + relation = peer.PARTNER + } + data := request.UpdateOne(map[string]interface{}{ + "relation": relation, + }, dest.GetID()) + + o.Data["json"] = data + o.ServeJSON() + return + } + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 400, + "error": "peer not found.", + } o.ServeJSON() } diff --git a/go.mod b/go.mod index 61a7ac6..ec6377c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.6 toolchain go1.24.11 require ( - cloud.o-forge.io/core/oc-lib v0.0.0-20260115122757-1c3b9218f7fb + cloud.o-forge.io/core/oc-lib v0.0.0-20260123065115-f3d7c65b18d1 github.com/beego/beego/v2 v2.3.8 github.com/smartystreets/goconvey v1.7.2 ) diff --git a/go.sum b/go.sum index 043d8ae..8d70d8f 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,18 @@ cloud.o-forge.io/core/oc-lib v0.0.0-20260115112656-7c5d5c491f41 h1:O82m02OUvyVSe cloud.o-forge.io/core/oc-lib v0.0.0-20260115112656-7c5d5c491f41/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= cloud.o-forge.io/core/oc-lib v0.0.0-20260115122757-1c3b9218f7fb h1:blCzhIrRW1gLTsAVVxFxfhA5LXenxiVNT4kn1MTphLg= cloud.o-forge.io/core/oc-lib v0.0.0-20260115122757-1c3b9218f7fb/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122131802-b98728675928 h1:/JATUIWRD632NX+89nxawYPSCUETwy+v0yp6l6F5HkM= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122131802-b98728675928/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122145527-00bcca379fe6 h1:P2ocksh1qJ/7LDfVvKzqg8KudZgn43Bp4ATQeY00wmI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122145527-00bcca379fe6/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122151154-8f5f3e331d1d h1:kSzGiETAjBHUS582OB8c1fIIsk3Agx550Pk1tE3GWBg= +cloud.o-forge.io/core/oc-lib v0.0.0-20260122151154-8f5f3e331d1d/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260123063820-b71b1e741d8c h1:Vq3/bZJ4GUIPo4tyJLSDRwLC1d+sxJCkmZbZzTHu27c= +cloud.o-forge.io/core/oc-lib v0.0.0-20260123063820-b71b1e741d8c/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= +cloud.o-forge.io/core/oc-lib v0.0.0-20260123064804-d06c9e933783 h1:ztJplXt5FIrSTB7quEFRYUaMrZTxuIN/OJaJ4hBBtXc= +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/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= 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/go.mod h1:8vl9+RrXqvodrl9C8yivX1e6le6deCK6RWeq8R7gTTg= diff --git a/infrastructure/dht.go b/infrastructure/dht.go index 7286d02..dbe982e 100644 --- a/infrastructure/dht.go +++ b/infrastructure/dht.go @@ -26,6 +26,7 @@ type DHTRecord struct { PeerID string PubKey []byte URL string + NATSUrl string Signature []byte ExpiryDate time.Time } @@ -63,20 +64,19 @@ func Init(ctx context.Context) (*DHTService, error) { return nil, err } singletonService = service - for { - if VerifyPubWithPriv() { - o := oclib.GetConfLoader() - if _, err := singletonService.ClaimName(context.Background(), o.GetStringDefault("NAME", "local"), o.GetStringDefault("HOSTNAME", "http://localhost")); err == nil { - go func() { - for { - singletonService.RefreshName(context.Background()) - time.Sleep(59 * time.Minute) - } - }() - } + if VerifyPubWithPriv() { + if _, err := singletonService.ClaimName(context.Background(), + conf.GetConfig().Name, + conf.GetConfig().Hostname); err == nil { + go func() { + for { + singletonService.RefreshName(context.Background()) + time.Sleep(59 * time.Minute) + } + }() } - break } + return service, service.DHT.Bootstrap(ctx) } @@ -106,6 +106,7 @@ func (d *DHTService) ClaimName( rec.Signature = sig rec.URL = endPoint + rec.NATSUrl = oclib.GetConfig().NATSUrl rec.State = peer.ONLINE.EnumIndex() rec.ExpiryDate = expiry @@ -145,6 +146,7 @@ func (d *DHTService) ClaimName( PeerID: d.Host.ID().String(), PublicKey: pubStr, Url: endPoint, + NATSUrl: oclib.GetConfig().NATSUrl, WalletAddress: "my-wallet", } if founded, _, err := access.Search(nil, fmt.Sprintf("%v", peer.SELF.EnumIndex()), false); err != nil || len(founded) == 0 { @@ -200,6 +202,7 @@ func (d *DHTService) treatPeer(ctx context.Context, key string, data []byte) (*p PeerID: rec.PeerID, PublicKey: pubStr, Url: rec.URL, + NATSUrl: rec.NATSUrl, } access := peer.NewAccessor(&tools.APIRequest{Admin: true}) if now.After(rec.ExpiryDate) { @@ -291,7 +294,6 @@ func (d *DHTService) existsDHT(ctx context.Context) (*DHTRecord, error) { Name: rec.Name, PeerID: rec.PeerID, PubKey: rec.PubKey, - URL: rec.URL, } payload, _ := json.Marshal(dht) @@ -325,6 +327,7 @@ func (d *DHTService) RefreshName( // peer should regulary refresh your host to n 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) diff --git a/main.go b/main.go index ba3ecb1..3ee559c 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,8 @@ func main() { o.GetStringDefault("LOG_LEVEL", "info"), ) + conf.GetConfig().Name = o.GetStringDefault("NAME", "local") + conf.GetConfig().Hostname = o.GetStringDefault("HOSTNAME", "http://localhost") conf.GetConfig().PublicKeyPath = o.GetStringDefault("PUBLIC_KEY_PATH", "./pem/public.pem") conf.GetConfig().PrivateKeyPath = o.GetStringDefault("PRIVATE_KEY_PATH", "./pem/private.pem") conf.GetConfig().DHTEndpointPort = o.GetInt64Default("DHT_ENDPOINT_PORT", 80)