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. */