Files
oc-peer/controllers/peer.go
T
2026-06-01 10:30:36 +02:00

540 lines
17 KiB
Go

package controllers
import (
ctx "context"
"encoding/json"
"fmt"
"oc-peer/infrastructure"
"strconv"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/config"
"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"
"github.com/gorilla/websocket"
)
// Operations about workflow
type PeerController struct {
beego.Controller
}
// @Title Search
// @Description search workspace
// @Param type path string true "the type you want to get"
// @Param search path string true "the word search you want to get"
// @Param is_draft query string false
// @Param offset query string false
// @Param limit query string false
// @Success 200 {workspace} models.workspace
// @router /:type/search/:search [get]
func (o *PeerController) Search() {
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
// store and return Id or post with UUIDLibDataEnum
search := o.Ctx.Input.Param(":search")
typ := o.Ctx.Input.Param(":type")
isDraft := o.Ctx.Input.Query("is_draft")
offset, _ := strconv.Atoi(o.Ctx.Input.Query("offset"))
limit, _ := strconv.Atoi(o.Ctx.Input.Query("limit"))
var filter *dbs.Filters
fmt.Println("TYP", typ)
relation := peer.GetRelationPath(typ)
if relation != -1 {
filter = &dbs.Filters{
And: map[string][]dbs.Filter{ // search by name if no filters are provided
"relation": {{Operator: dbs.EQUAL.String(), Value: relation}},
},
Or: map[string][]dbs.Filter{ // search by name if no filters are providedz
"abstractobject.name": {{Operator: dbs.LIKE.String(), Value: search}},
"url": {{Operator: dbs.LIKE.String(), Value: search}},
"peer_id": {{Operator: dbs.LIKE.String(), Value: search}},
},
}
search = ""
}
fmt.Println(filter, relation, "<", search, ">")
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(
filter, search, isDraft == "true", int64(offset), int64(limit))
o.ServeJSON()
}
// @Title Search
// @Description search workspace
// @Param is_draft query string false
// @Param offset query string false
// @Param limit query string false
// @Param data body json true "body for data content (Json format)"
// @Success 200 {workspace} models.workspace
// @router /:type/extended/search [post]
func (o *PeerController) SearchExtended() {
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
// store and return Id or post with UUIDLibDataEnum
isDraft := o.Ctx.Input.Query("is_draft")
typ := o.Ctx.Input.Param(":type")
offset, _ := strconv.Atoi(o.Ctx.Input.Query("offset"))
limit, _ := strconv.Atoi(o.Ctx.Input.Query("limit"))
var res map[string]interface{}
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &res)
fmt.Println(res, oclib.FiltersFromFlatMap(res, &peer.Peer{}))
relation := peer.GetRelationPath(typ)
res["relation"] = relation
data := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(
oclib.FiltersFromFlatMap(res, &peer.Peer{}), "", isDraft == "true", int64(offset), int64(limit))
o.Data["json"] = data
o.ServeJSON()
}
// @Title GetAll
// @Description find all peer
// @Param is_draft query string false
// @Param offset query string false
// @Param limit query string false
// @Success 200 {peer} models.peer
// @router / [get]
func (o *PeerController) GetAll() {
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
isDraft := o.Ctx.Input.Query("is_draft")
offset, _ := strconv.Atoi(o.Ctx.Input.Query("offset"))
limit, _ := strconv.Atoi(o.Ctx.Input.Query("limit"))
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, int64(offset), int64(limit))
} else {
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).LoadAll(isDraft == "true", int64(offset), int64(limit))
}
o.ServeJSON()
}
// @Title Get
// @Description find peer by peerid
// @Param id path string true "the peer id you want to get"
// @Success 200 {peer} models.peer
// @router /:id [get]
func (o *PeerController) Get() {
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).LoadOne(id)
o.ServeJSON()
}
// @Title Valid
// @Description find peer by peerid
// @Param id path string true "the peer id you want to get"
// @Success 200 {peer} models.peer
// @router /valid/:id [get]
func (o *PeerController) Valid() {
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
if ok, _ := oclib.IsMySelf(id); ok {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 400,
"error": "can't validate a link relation for ourself",
}
o.ServeJSON()
return
}
fmt.Println(id)
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
l := req.LoadOne(id)
if l.Data != nil && l.ToPeer().Verify && (l.ToPeer().Relation == peer.PARTNER || l.ToPeer().Relation == peer.PENDING_PARTNER) {
data := req.UpdateOne(map[string]interface{}{
"verify": false,
"relation": peer.PARTNER,
}, l.ToPeer().GetID())
fmt.Println(l.Data, data.Data)
if data.Data != nil {
b, _ := json.Marshal(data.Data)
go infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{
DataType: tools.PEER.EnumIndex(),
Action: tools.PB_CREATE,
Payload: b,
})
}
o.Data["json"] = data
o.ServeJSON()
return
} else if l.Data != nil && l.ToPeer().Verify && (l.ToPeer().Relation == peer.MASTER || l.ToPeer().Relation == peer.PENDING_MASTER) {
masterPeerID := l.ToPeer().PeerID
data := req.UpdateOne(map[string]interface{}{
"verify": false,
"relation": peer.MASTER,
}, l.ToPeer().GetID())
fmt.Println(l.Data, data.Data)
data.Data.(*peer.Peer).MasterID = masterPeerID
data.Data.(*peer.Peer).Relation = peer.NANO // dest is a nano
if data.Data != nil {
b, _ := json.Marshal(data.Data)
go infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{
DataType: tools.PEER.EnumIndex(),
Action: tools.PB_CREATE,
Payload: b,
})
}
// This node is now a NANO of the confirmed master: stamp its libp2p PeerID on self.
if self, serr := oclib.GetMySelf(); serr == nil && self != nil {
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).UpdateOne(map[string]interface{}{
"master_id": masterPeerID,
}, self.GetID())
}
o.Data["json"] = data
o.ServeJSON()
return
} else if l.Data != nil && l.ToPeer().Verify && (l.ToPeer().Relation == peer.NANO || l.ToPeer().Relation == peer.PENDING_NANO) {
masterPeerID, err := oclib.GetMySelf()
if err == nil {
data := req.UpdateOne(map[string]interface{}{
"verify": false,
"relation": peer.NANO,
}, l.ToPeer().GetID())
fmt.Println(l.Data, data.Data)
data.Data.(*peer.Peer).MasterID = masterPeerID.GetID()
data.Data.(*peer.Peer).Relation = peer.MASTER // dest is a nano
if data.Data != nil {
b, _ := json.Marshal(data.Data)
go infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{
DataType: tools.PEER.EnumIndex(),
Action: tools.PB_CREATE,
Payload: b,
})
}
// This node is now a NANO of the confirmed master: stamp its libp2p PeerID on self.
if self, serr := oclib.GetMySelf(); serr == nil && self != nil {
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).UpdateOne(map[string]interface{}{
"master_id": masterPeerID.GetID(),
}, self.GetID())
}
o.Data["json"] = data
o.ServeJSON()
return
}
}
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 404,
"error": "peer to verify not found",
}
o.ServeJSON()
}
// @Title add
// @Description add peer by peerid
// @Param id path string true "the peer id you want to blacklist"
// @Success 200 {peer} models.peer
// @router /add/:id [post]
func (o *PeerController) Add() {
user, _, _ := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
infrastructure.SearchMu.Lock()
defer infrastructure.SearchMu.Unlock()
fmt.Println("qdqqds", infrastructure.SearchStreamAction)
if infrastructure.SearchStreamAction[user] != nil {
for _, p := range infrastructure.SearchStreamAction[user] {
if p.GetID() == id {
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
p.NotInCatalog = false
o.Data["json"] = req.StoreOne(p.Serialize(p))
o.ServeJSON()
return
}
}
}
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 404,
"error": "peer not received found",
}
o.ServeJSON()
}
// @Title Master
// @Description add master peer by peerid
// @Param id path string true "the peer id you want to blacklist"
// @Success 200 {peer} models.peer
// @router /master/:id [post]
func (o *PeerController) Master() {
if !config.GetConfig().IsNano {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "not nano built can't ask for master",
}
}
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
data := req.LoadOne(id)
p := data.ToPeer()
if p.IsNano {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "is not Master built can't ask for master",
}
}
o.changeRelation(id, p, user, groups, peer.MASTER, req)
}
// @Title Nano
// @Description add Nano peer by peerid
// @Param id path string true "the peer id you want to blacklist"
// @Success 200 {peer} models.peer
// @router /nano/:id [post]
func (o *PeerController) Nano() {
if config.GetConfig().IsNano {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "nano built can't ask for nano",
}
}
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
data := req.LoadOne(id)
p := data.ToPeer()
if !p.IsNano {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "is not Nano built can't ask for nano",
}
}
o.changeRelation(id, p, user, groups, peer.NANO, req)
}
// @Title known
// @Description add kwown peer by peerid
// @Param id path string true "the peer id you want to blacklist"
// @Success 200 {peer} models.peer
// @router /known/:id [post]
func (o *PeerController) Known() {
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
data := req.LoadOne(id)
o.changeRelation(id, data.ToPeer(), user, groups, 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 /partner/:id [post]
func (o *PeerController) Partner() {
if config.GetConfig().IsNano {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "nano built can't ask for partner",
}
}
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
data := req.LoadOne(id)
o.changeRelation(id, data.ToPeer(), user, groups, peer.PARTNER, req)
}
// @Title Blacklist
// @Description add blacklist peer by peerid
// @Param id path string true "the peer id you want to blacklist"
// @Success 200 {peer} models.peer
// @router /blacklist/:id [post]
func (o *PeerController) Blacklist() {
user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
data := req.LoadOne(id)
o.changeRelation(id, data.ToPeer(), user, groups, peer.BLACKLIST, req)
}
// used from : peer ask, or response, only from peer origin is authorized to change...
func (o *PeerController) changeRelation(id string, dest *peer.Peer, user string, groups []string, relation peer.PeerRelation, request *oclib.Request) {
if dest.IsNano && relation != peer.NANO {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 409,
"error": "can't change relation on nano",
}
o.ServeJSON()
return
}
infrastructure.SearchMu.Lock()
if dest == nil && infrastructure.SearchStreamAction[user] != nil { // add auto in base if not existing
req := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
for _, pp := range infrastructure.SearchStreamAction[user] {
if pp.GetID() == id {
data := req.StoreOne(pp.Serialize(pp))
dest = data.ToPeer()
break
}
}
}
infrastructure.SearchMu.Unlock()
// store and return Id or post with UUID
if dest != nil {
if ok, _ := oclib.IsMySelf(dest.GetID()); ok {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 400,
"error": "can't change ourself",
}
o.ServeJSON()
return
}
rRelation := relation
if !dest.Verify {
switch relation {
case peer.PARTNER:
relation = peer.PENDING_PARTNER
case peer.NANO:
relation = peer.PENDING_NANO
case peer.BLACKLIST:
relation = peer.NONE
}
}
if dest.Verify && relation == peer.PENDING_PARTNER {
relation = peer.PARTNER
}
if dest.Verify && relation == peer.PENDING_NANO {
relation = peer.NANO
}
wasMaster := dest.Relation == peer.MASTER
data := request.UpdateOne(map[string]interface{}{
"relation": relation,
}, dest.GetID())
fmt.Println(data.Err, data.Data)
if data.Err == "" && data.Data != nil {
b, _ := json.Marshal(data.Data)
go infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{
DataType: tools.PEER.EnumIndex(),
Action: tools.PB_CREATE,
Payload: b,
})
}
// The peer was our master and is no longer — clear the MasterID on self.
if wasMaster {
if self, serr := oclib.GetMySelf(); serr == nil && self != nil {
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).UpdateOne(map[string]interface{}{
"master_id": "",
}, self.GetID())
}
}
if rRelation == peer.BLACKLIST {
request.UpdateOne(map[string]interface{}{
"relation": rRelation,
}, dest.GetID())
}
o.Data["json"] = data
o.ServeJSON()
return
}
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 404,
"error": "peer not found.",
}
o.ServeJSON()
}
// @Title Delete
// @Description delete peer by peerid
// @Param id path string true "the peer id you want to delete state"
// @Success 200 {peer} models.peer
// @router /:id [delete]
func (o *PeerController) Delete() {
id := o.Ctx.Input.Param(":id")
if ok, _ := oclib.IsMySelf(id); ok {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 400,
"error": "can't remove myself",
}
o.ServeJSON()
return
}
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).DeleteOne(id)
fmt.Println(o.Data["json"])
o.ServeJSON()
}
func Websocket(c ctx.Context, user string, conn *websocket.Conn) {
defer conn.Close()
done := make(chan struct{})
go func() {
var discard interface{}
for {
if conn.ReadJSON(&discard) != nil {
close(done)
return
}
}
}()
defer func() {
if ch, ok := infrastructure.SearchStream[user]; ok {
close(ch)
infrastructure.SearchMu.Lock()
delete(infrastructure.SearchStream, user)
delete(infrastructure.SearchStreamAction, user)
fmt.Println("DEFER")
infrastructure.SearchMu.Unlock()
}
infrastructure.EmitNATS(user, nil, tools.PropalgationMessage{
Action: tools.PB_CLOSE_SEARCH,
DataType: tools.PEER.EnumIndex(),
})
}()
for {
select {
case msg, ok := <-infrastructure.SearchStream[user]:
if !ok {
continue
}
// Only accumulate peers in the action list (not online-change events).
if msg.Peer != nil {
fmt.Println("AAADDD")
infrastructure.SearchMu.Lock()
infrastructure.SearchStreamAction[user] = append(infrastructure.SearchStreamAction[user], msg.Peer)
infrastructure.SearchMu.Unlock()
fmt.Println("AAADDD", infrastructure.SearchStreamAction[user])
}
if conn.WriteJSON(msg) != nil {
continue
}
case <-done:
return
case <-c.Done():
return
}
}
}
/*
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.
*/