diff --git a/controllers/compute.go b/controllers/compute.go deleted file mode 100755 index 12e309a..0000000 --- a/controllers/compute.go +++ /dev/null @@ -1,124 +0,0 @@ -package controllers - -import ( - "encoding/json" - "oc-catalog/infrastructure" - - oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/tools" - beego "github.com/beego/beego/v2/server/web" -) - -// Operations about compute -type ComputeController struct { - beego.Controller -} - -var comp_collection = oclib.LibDataEnum(oclib.COMPUTE_RESOURCE) -var comp_dt = tools.COMPUTE_RESOURCE - -// @Title Update -// @Description create computes -// @Param id path string true "the compute id you want to get" -// @Param body body models.compute true "The compute content" -// @Success 200 {compute} models.compute -// @router /:id [put] -func (o *ComputeController) Put() { - user, _, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - // store and return Id or post with UUID - var res map[string]interface{} - id := o.Ctx.Input.Param(":id") - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequestAdmin(comp_collection, nil).UpdateOne(res, id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_UPDATE, - DataType: comp_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title Create -// @Description create compute -// @Param compute body json true "body for compute content (Json format)" -// @Success 200 {compute} models.compute -// @router / [post] -func (o *ComputeController) Post() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(comp_collection, user, peerID, groups, nil).StoreOne(res) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_CREATE, - DataType: comp_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title GetAll -// @Description find compute by id -// @Param is_draft query string false "draft wished" -// @Success 200 {compute} models.compute -// @router / [get] -func (o *ComputeController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(comp_collection, user, peerID, groups, nil).LoadAll(isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find compute by key word -// @Param search path string true "the search you want to get" -// @Param is_draft query string false "draft wished" -// @Success 200 {compute} models.compute -// @router /search/:search [get] -func (o *ComputeController) Search() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - search := o.Ctx.Input.Param(":search") - o.Data["json"] = oclib.NewRequest(comp_collection, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find compute by id -// @Param id path string true "the id you want to get" -// @Success 200 {compute} models.compute -// @router /:id [get] -func (o *ComputeController) Get() { - // user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequestAdmin(comp_collection, nil).LoadOne(id) - o.ServeJSON() -} - -// @Title Delete -// @Description delete the compute -// @Param id path string true "The id you want to delete" -// @Success 200 {compute} delete success! -// @router /:id [delete] -func (o *ComputeController) Delete() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - data := oclib.NewRequest(comp_collection, user, peerID, groups, nil).DeleteOne(id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_DELETE, - DataType: comp_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = oclib.NewRequest(comp_collection, user, peerID, groups, nil).DeleteOne(id) - o.ServeJSON() -} diff --git a/controllers/data.go b/controllers/data.go deleted file mode 100755 index 3a270c9..0000000 --- a/controllers/data.go +++ /dev/null @@ -1,125 +0,0 @@ -package controllers - -import ( - "encoding/json" - "oc-catalog/infrastructure" - - oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/tools" - beego "github.com/beego/beego/v2/server/web" -) - -// Operations about data -type DataController struct { - beego.Controller -} - -var data_collection = oclib.LibDataEnum(oclib.DATA_RESOURCE) -var data_dt = tools.DATA_RESOURCE - -// @Title Update -// @Description create datas -// @Param id path string true "the data id you want to get" -// @Param body body models.data true "The data content" -// @Success 200 {data} models.data -// @router /:id [put] -func (o *DataController) 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(data_collection, user, peerID, groups, nil).UpdateOne(res, id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_UPDATE, - DataType: data_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title Create -// @Description create data -// @Param data body json true "body for data content (Json format)" -// @Success 200 {data} models.data -// @router / [post] -func (o *DataController) Post() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(data_collection, user, peerID, groups, nil).StoreOne(res) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_CREATE, - DataType: data_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title GetAll -// @Description find data by id -// @Param is_draft query string false "draft wished" -// @Success 200 {data} models.data -// @router / [get] -func (o *DataController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(data_collection, user, peerID, groups, nil).LoadAll(isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find data by key word -// @Param search path string true "the search you want to get" -// @Param is_draft query string false "draft wished" - -// @Success 200 {data} models.data -// @router /search/:search [get] -func (o *DataController) Search() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - search := o.Ctx.Input.Param(":search") - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(data_collection, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find data by id -// @Param id path string true "the id you want to get" -// @Success 200 {data} models.data -// @router /:id [get] -func (o *DataController) Get() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequest(data_collection, user, peerID, groups, nil).LoadOne(id) - o.ServeJSON() -} - -// @Title Delete -// @Description delete the data -// @Param id path string true "The id you want to delete" -// @Success 200 {data} delete success! -// @router /:id [delete] -func (o *DataController) Delete() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - data := oclib.NewRequest(data_collection, user, peerID, groups, nil).DeleteOne(id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_DELETE, - DataType: data_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} diff --git a/controllers/general.go b/controllers/general.go index 7e2a412..1f654ad 100755 --- a/controllers/general.go +++ b/controllers/general.go @@ -2,15 +2,15 @@ package controllers import ( "context" + "encoding/json" "fmt" - "net/http" "oc-catalog/infrastructure" oclib "cloud.o-forge.io/core/oc-lib" w "cloud.o-forge.io/core/oc-lib/models/workflow" tools "cloud.o-forge.io/core/oc-lib/tools" beego "github.com/beego/beego/v2/server/web" - "golang.org/x/net/websocket" + "github.com/gorilla/websocket" ) // Operations about compute @@ -63,47 +63,49 @@ func (o *GeneralController) GetAll() { o.ServeJSON() } -func Websocket(ctx context.Context, user string, groups []string, dataType int, r http.ResponseWriter, w *http.Request) { - websocket.Handler(func(ws *websocket.Conn) { - done := make(chan struct{}) - go func() { - var discard interface{} - for { - if websocket.JSON.Receive(ws, &discard) != nil { - close(done) - return - } - } - }() - defer func() { - ws.Close() - if ch, ok := infrastructure.SearchStream[user]; ok { - close(ch) - infrastructure.SearchMu.Lock() - delete(infrastructure.SearchStream, user) - infrastructure.SearchMu.Unlock() - } - fmt.Println("CLOSE !") - infrastructure.EmitNATS(user, nil, tools.PropalgationMessage{ - Action: tools.PB_CLOSE_SEARCH, - DataType: dataType, - }) - }() +func Websocket(ctx context.Context, user string, groups []string, dataType int, conn *websocket.Conn) { + defer conn.Close() + done := make(chan struct{}) + go func() { + var discard interface{} for { - select { - case msg, ok := <-infrastructure.SearchStream[user]: - fmt.Println("FOR", msg, ok) - if !ok { - continue - } - if websocket.JSON.Send(ws, msg) != nil { - continue - } - case <-done: - return - case <-ctx.Done(): + if err := conn.ReadJSON(&discard); err != nil { + close(done) return } } - }).ServeHTTP(r, w) + }() + defer func() { + if ch, ok := infrastructure.SearchStream[user]; ok { + close(ch) + infrastructure.SearchMu.Lock() + delete(infrastructure.SearchStream, user) + infrastructure.SearchMu.Unlock() + } + fmt.Println("CLOSE !") + infrastructure.EmitNATS(user, nil, tools.PropalgationMessage{ + Action: tools.PB_CLOSE_SEARCH, + DataType: dataType, + }) + }() + for { + select { + case msg, ok := <-infrastructure.SearchStream[user]: + if !ok { + continue + } + m := map[string]interface{}{} + if err := json.Unmarshal(msg, &m); err == nil { + if err := conn.WriteJSON(m); err != nil { + continue + } + } else { + continue + } + case <-done: + return + case <-ctx.Done(): + return + } + } } diff --git a/controllers/processing.go b/controllers/processing.go deleted file mode 100755 index ef79d81..0000000 --- a/controllers/processing.go +++ /dev/null @@ -1,126 +0,0 @@ -package controllers - -import ( - "encoding/json" - "fmt" - "oc-catalog/infrastructure" - - oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/tools" - beego "github.com/beego/beego/v2/server/web" -) - -// Operations about processing -type ProcessingController struct { - beego.Controller -} - -var processing_collection = oclib.LibDataEnum(oclib.PROCESSING_RESOURCE) -var processing_dt = tools.PROCESSING_RESOURCE - -// @Title Update -// @Description create processings -// @Param id path string true "the processing id you want to get" -// @Param body body models.processing true "The processing content" -// @Success 200 {processing} models.processing -// @router /:id [put] -func (o *ProcessingController) Put() { - // store and return Id or post with UUID - user, _, 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) - fmt.Println("Sqdqsqsd") - data := oclib.NewRequestAdmin(processing_collection, nil).UpdateOne(res, id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_UPDATE, - DataType: processing_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title Create -// @Description create processing -// @Param processing body json true "body for processing content (Json format)" -// @Success 200 {processing} models.processing -// @router / [post] -func (o *ProcessingController) Post() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(processing_collection, user, peerID, groups, nil).StoreOne(res) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_CREATE, - DataType: processing_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title GetAll -// @Description find processing by id -// @Param is_draft query string false "draft wished" -// @Success 200 {processing} models.processing -// @router / [get] -func (o *ProcessingController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(processing_collection, user, peerID, groups, nil).LoadAll(isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find processing by key word -// @Param search path string true "the search you want to get" -// @Param is_draft query string false "draft wished" -// @Success 200 {processing} models.processing -// @router /search/:search [get] -func (o *ProcessingController) Search() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - search := o.Ctx.Input.Param(":search") - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(processing_collection, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find processing by id -// @Param id path string true "the id you want to get" -// @Success 200 {processing} models.processing -// @router /:id [get] -func (o *ProcessingController) Get() { - // user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequestAdmin(processing_collection, nil).LoadOne(id) - o.ServeJSON() -} - -// @Title Delete -// @Description delete the processing -// @Param id path string true "The id you want to delete" -// @Success 200 {processing} delete success! -// @router /:id [delete] -func (o *ProcessingController) Delete() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - data := oclib.NewRequest(processing_collection, user, peerID, groups, nil).DeleteOne(id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_DELETE, - DataType: processing_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} diff --git a/controllers/resource.go b/controllers/resource.go index 330cb3c..63cfbb0 100755 --- a/controllers/resource.go +++ b/controllers/resource.go @@ -1,85 +1,221 @@ package controllers import ( - "fmt" + "encoding/json" + "oc-catalog/infrastructure" oclib "cloud.o-forge.io/core/oc-lib" + "cloud.o-forge.io/core/oc-lib/models/utils" + "cloud.o-forge.io/core/oc-lib/tools" beego "github.com/beego/beego/v2/server/web" ) -// Operations about resource +// ResourceController aggregates all resource types. type ResourceController struct { beego.Controller } -// @Title GetAll -// @Description find resource by id -// @Param is_draft query string false "draft wished" -// @Success 200 {resource} models.resource -// @router / [get] -func (o *ResourceController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - results := map[string]interface{}{} - isDraft := o.Ctx.Input.Query("is_draft") - for _, resource := range []oclib.LibDataEnum{ - data_collection, comp_collection, storage_collection, - processing_collection, workflow_collection} { - d := oclib.NewRequest(resource, user, peerID, groups, nil).LoadAll(isDraft == "true") - if d.Code != 200 || len(d.Data) == 0 { - results[resource.String()] = []interface{}{} - } else { - results[resource.String()] = d.Data - } +func resourceTypeEnum(t string, special bool) []oclib.LibDataEnum { + e := []oclib.LibDataEnum{} + if special && t == "resource" { + return e } - o.Data["json"] = map[string]interface{}{"data": results, "code": 200, "error": ""} + if t == "compute" || t == "resource" { + e = append(e, oclib.LibDataEnum(oclib.COMPUTE_RESOURCE)) + } + if t == "data" || t == "resource" { + e = append(e, oclib.LibDataEnum(oclib.DATA_RESOURCE)) + } + if t == "storage" || t == "resource" { + e = append(e, oclib.LibDataEnum(oclib.STORAGE_RESOURCE)) + } + if t == "processing" || t == "resource" { + e = append(e, oclib.LibDataEnum(oclib.PROCESSING_RESOURCE)) + } + if t == "workflow" || t == "resource" { + e = append(e, oclib.LibDataEnum(oclib.WORKFLOW_RESOURCE)) + } + return e +} + +func (o *ResourceController) collection(special bool) []oclib.LibDataEnum { + // Extrait le type depuis le segment d'URL après "resource" + // URL forme: /oc/resource/{type}/... + typ := o.Ctx.Input.Param(":type") + return resourceTypeEnum(typ, special) +} + +func (o *ResourceController) notFound() { + o.Ctx.Output.SetStatus(404) + o.Data["json"] = map[string]interface{}{"error": "unknown resource type", "code": 404, "data": nil} o.ServeJSON() } -// @Title Get -// @Description find resource by key word +// @Title GetAll +// @Description list all resources across all types +// @Param type path string true "the type you want to get" +// @Param is_draft query string false "draft wished" +// @Success 200 {resource} models.resource +// @router /:type [get] +func (o *ResourceController) GetAll() { + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + isDraft := o.Ctx.Input.Query("is_draft") + + m := map[string][]utils.ShallowDBObject{} + for _, col := range o.collection(false) { + if m[col.String()] == nil { + m[col.String()] = []utils.ShallowDBObject{} + } + s := oclib.NewRequest(col, user, peerID, groups, nil).LoadAll(isDraft == "true") + m[col.String()] = append(m[col.String()], s.Data...) + } + o.Data["json"] = map[string]interface{}{ + "data": m, + "code": 200, + "err": nil, + } + o.ServeJSON() +} + +// @Title Search +// @Description search resources across all types +// @Param type path string true "the type you want to get" // @Param search path string true "the search you want to get" // @Param is_draft query string false "draft wished" // @Success 200 {resource} models.resource -// @router /search/:search [get] +// @router /:type/search/:search [get] func (o *ResourceController) Search() { user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - search := o.Ctx.Input.Param(":search") isDraft := o.Ctx.Input.Query("is_draft") - results := map[string]interface{}{} - for _, resource := range []oclib.LibDataEnum{ - data_collection, comp_collection, storage_collection, - processing_collection, workflow_collection} { - fmt.Println("search", search) - d := oclib.NewRequest(resource, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - if d.Code != 200 || len(d.Data) == 0 { - results[resource.String()] = []interface{}{} - } else { - results[resource.String()] = d.Data + search := o.Ctx.Input.Param(":search") + + m := map[string][]utils.ShallowDBObject{} + for _, col := range o.collection(false) { + if m[col.String()] == nil { + m[col.String()] = []utils.ShallowDBObject{} } + s := oclib.NewRequest(col, user, peerID, groups, nil).Search(nil, search, isDraft == "true") + m[col.String()] = append(m[col.String()], s.Data...) + + } + o.Data["json"] = map[string]interface{}{ + "data": m, + "code": 200, + "err": nil, } - o.Data["json"] = map[string]interface{}{"data": results, "code": 200, "error": ""} o.ServeJSON() } // @Title Get -// @Description find resource by id +// @Description search resources across all types +// @Param type path string true "the type you want to get" // @Param id path string true "the id you want to get" +// @Param is_draft query string false "draft wished" // @Success 200 {resource} models.resource -// @router /:id [get] +// @router /:type/:id [get] func (o *ResourceController) Get() { user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) id := o.Ctx.Input.Param(":id") - results := map[string]interface{}{} - for _, resource := range []oclib.LibDataEnum{ - data_collection, comp_collection, storage_collection, - processing_collection, workflow_collection} { - d := oclib.NewRequest(resource, user, peerID, groups, nil).LoadOne(id) - if d.Code != 200 { - results[resource.String()] = nil + + for _, col := range o.collection(false) { + if d := oclib.NewRequest(col, user, peerID, groups, nil).LoadOne(id); d.Data != nil { + o.Data["json"] = d + break } else { - results[resource.String()] = d.Data + o.Data["json"] = d + } + } + o.ServeJSON() +} + +// @Title Post +// @Description search resources across all types +// @Param type path string true "the type you want to get" +// @Param data body json true "body for data content (Json format)" +// @Success 200 {resource} models.resource +// @router /:type [post] +func (o *ResourceController) Post() { + libs := o.collection(true) + if len(libs) == 0 { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 500, + "err": "not a proper type", + } + } + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + var res map[string]interface{} + json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) + data := oclib.NewRequest(libs[0], user, peerID, groups, nil).StoreOne(res) + if data.Err == "" { + payload, _ := json.Marshal(data.Data.Serialize(data.Data)) + infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ + Action: tools.PB_CREATE, + DataType: libs[0].EnumIndex(), + Payload: payload, + }) + } + o.Data["json"] = data + o.ServeJSON() +} + +// @Title Put +// @Description search resources across all types +// @Param type path string true "the type you want to get" +// @Param id path string true "the id you want to get" +// @Param data body json true "body for data content (Json format)" +// @Success 200 {resource} models.resource +// @router /:type/:id [put] +func (o *ResourceController) Put() { + libs := o.collection(true) + if len(libs) == 0 { + o.Data["json"] = map[string]interface{}{ + "data": nil, + "code": 500, + "err": "not a proper type", + } + } + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + id := o.Ctx.Input.Param(":id") + var res map[string]interface{} + json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) + data := oclib.NewRequest(libs[0], user, peerID, groups, nil).UpdateOne(res, id) + if data.Err == "" { + payload, _ := json.Marshal(data.Data.Serialize(data.Data)) + infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ + Action: tools.PB_UPDATE, + DataType: libs[0].EnumIndex(), + Payload: payload, + }) + } + o.Data["json"] = data + o.ServeJSON() +} + +// @Title Delete +// @Description search resources across all types +// @Param type path string true "the type you want to get" +// @Param id path string true "the id you want to get" +// @Param is_draft query string false "draft wished" +// @Success 200 {resource} models.resource +// @router /:type/:id [delete] +func (o *ResourceController) Delete() { + user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) + id := o.Ctx.Input.Param(":id") + for _, col := range o.collection(false) { + data := oclib.NewRequest(col, user, peerID, groups, nil).DeleteOne(id) + if data.Err == "" { + o.Data["json"] = data + payload, _ := json.Marshal(data.Data.Serialize(data.Data)) + infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ + Action: tools.PB_DELETE, + DataType: col.EnumIndex(), + Payload: payload, + }) + break + } else { + o.Data["json"] = data } } - o.Data["json"] = map[string]interface{}{"data": results, "code": 200, "error": ""} o.ServeJSON() } diff --git a/controllers/storage.go b/controllers/storage.go deleted file mode 100755 index cdd9570..0000000 --- a/controllers/storage.go +++ /dev/null @@ -1,124 +0,0 @@ -package controllers - -import ( - "encoding/json" - "oc-catalog/infrastructure" - - oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/tools" - beego "github.com/beego/beego/v2/server/web" -) - -// Operations about storage -type StorageController struct { - beego.Controller -} - -var storage_collection = oclib.LibDataEnum(oclib.STORAGE_RESOURCE) -var storage_dt = tools.STORAGE_RESOURCE - -// @Title Update -// @Description create storages -// @Param id path string true "the storage id you want to get" -// @Param body body models.storage true "The storage content" -// @Success 200 {storage} models.storage -// @router /:id [put] -func (o *StorageController) 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(storage_collection, user, peerID, groups, nil).UpdateOne(res, id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_UPDATE, - DataType: storage_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title Create -// @Description create storage -// @Param storage body json true "body for storage content (Json format)" -// @Success 200 {storage} models.storage -// @router / [post] -func (o *StorageController) Post() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(storage_collection, user, peerID, groups, nil).StoreOne(res) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_CREATE, - DataType: storage_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title GetAll -// @Description find storage by id -// @Param is_draft query string false "draft wished" -// @Success 200 {storage} models.storage -// @router / [get] -func (o *StorageController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(storage_collection, user, peerID, groups, nil).LoadAll(isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find storage by key word -// @Param search path string true "the search you want to get" -// @Param is_draft query string false "draft wished" -// @Success 200 {storage} models.storage -// @router /search/:search [get] -func (o *StorageController) Search() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - search := o.Ctx.Input.Param(":search") - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(storage_collection, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find storage by id -// @Param id path string true "the id you want to get" -// @Success 200 {storage} models.storage -// @router /:id [get] -func (o *StorageController) Get() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequest(storage_collection, user, peerID, groups, nil).LoadOne(id) - o.ServeJSON() -} - -// @Title Delete -// @Description delete the storage -// @Param id path string true "The id you want to delete" -// @Success 200 {storage} delete success! -// @router /:id [delete] -func (o *StorageController) Delete() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - data := oclib.NewRequest(storage_collection, user, peerID, groups, nil).DeleteOne(id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_DELETE, - DataType: storage_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} diff --git a/controllers/workflow.go b/controllers/workflow.go deleted file mode 100755 index edb4d8c..0000000 --- a/controllers/workflow.go +++ /dev/null @@ -1,124 +0,0 @@ -package controllers - -import ( - "encoding/json" - "oc-catalog/infrastructure" - - oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/tools" - beego "github.com/beego/beego/v2/server/web" -) - -// Operations about workflow -type WorkflowController struct { - beego.Controller -} - -var workflow_collection = oclib.LibDataEnum(oclib.WORKFLOW_RESOURCE) -var workflow_dt = tools.WORKFLOW_RESOURCE - -// @Title Update -// @Description create workflows -// @Param id path string true "the workflow id you want to get" -// @Param body body models.workflow true "The workflow content" -// @Success 200 {workflow} models.workflow -// @router /:id [put] -func (o *WorkflowController) 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(workflow_collection, user, peerID, groups, nil).UpdateOne(res, id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_UPDATE, - Payload: data, - DataType: workflow_dt.EnumIndex(), - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title Create -// @Description create workflow -// @Param workflow body json true "body for workflow content (Json format)" -// @Success 200 {workflow} models.workflow -// @router / [post] -func (o *WorkflowController) Post() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - var res map[string]interface{} - json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res) - data := oclib.NewRequest(workflow_collection, user, peerID, groups, nil).StoreOne(res) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_CREATE, - DataType: workflow_dt.EnumIndex(), - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} - -// @Title GetAll -// @Description find workflow by id -// @Param is_draft query string false "draft wished" -// @Success 200 {workflow} models.workflow -// @router / [get] -func (o *WorkflowController) GetAll() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(workflow_collection, user, peerID, groups, nil).LoadAll(isDraft == "true") - o.ServeJSON() -} - -// @Title Search -// @Description find workflow by key word -// @Param search path string true "the search you want to get" -// @Param is_draft query string false "draft wished" -// @Success 200 {workflow} models.workflow -// @router /search/:search [get] -func (o *WorkflowController) Search() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - search := o.Ctx.Input.Param(":search") - isDraft := o.Ctx.Input.Query("is_draft") - o.Data["json"] = oclib.NewRequest(workflow_collection, user, peerID, groups, nil).Search(nil, search, isDraft == "true") - o.ServeJSON() -} - -// @Title Get -// @Description find workflow by id -// @Param id path string true "the id you want to get" -// @Success 200 {workflow} models.workflow -// @router /:id [get] -func (o *WorkflowController) Get() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - o.Data["json"] = oclib.NewRequest(workflow_collection, user, peerID, groups, nil).LoadOne(id) - o.ServeJSON() -} - -// @Title Delete -// @Description delete the workflow -// @Param id path string true "The id you want to delete" -// @Success 200 {workflow} delete success! -// @router /:id [delete] -func (o *WorkflowController) Delete() { - user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request) - id := o.Ctx.Input.Param(":id") - data := oclib.NewRequest(workflow_collection, user, peerID, groups, nil).DeleteOne(id) - if data.Err == "" { - data, _ := json.Marshal(data.Data.Serialize(data.Data)) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - DataType: workflow_dt.EnumIndex(), - Action: tools.PB_DELETE, - Payload: data, - }) - } - o.Data["json"] = data - o.ServeJSON() -} diff --git a/go.mod b/go.mod index 0d2d81e..ce56261 100755 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module oc-catalog go 1.25.0 require ( - cloud.o-forge.io/core/oc-lib v0.0.0-20260318074039-6a907236faec + cloud.o-forge.io/core/oc-lib v0.0.0-20260401110447-20cac09f9d6f github.com/beego/beego/v2 v2.3.8 + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/smartystreets/goconvey v1.7.2 ) @@ -19,7 +20,6 @@ require ( github.com/google/gnostic-models v0.7.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-libp2p/core v0.43.0-rc2 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -54,7 +54,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.27.0 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/uuid v1.6.0 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/goraz/onion v0.1.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -74,7 +74,6 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.17.0 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect github.com/smartystreets/assertions v1.2.0 // indirect diff --git a/go.sum b/go.sum index 6c465b9..043f589 100755 --- a/go.sum +++ b/go.sum @@ -1,100 +1,12 @@ -cloud.o-forge.io/core/oc-lib v0.0.0-20260128160440-c0d89ea9e1e8 h1:h7VHJktaTT8TxO4ld3Xjw3LzMsivr3m7mzbNxb44zes= -cloud.o-forge.io/core/oc-lib v0.0.0-20260128160440-c0d89ea9e1e8/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260128162702-97cf629e27ec h1:/uvrtEt7A5rwqFPHH8yjujlC33HMjQHhWDIK6I08DrA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260128162702-97cf629e27ec/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260129122033-186ba3e689c7 h1:NRFGRqN+j5g3DrtXMYN5T5XSYICG+OU2DisjBdID3j8= -cloud.o-forge.io/core/oc-lib v0.0.0-20260129122033-186ba3e689c7/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203074447-30e6c9a6183c h1:c19lIseiUk5Hp+06EowfEbMWH1pK8AC/hvQ4ryWgJtY= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203074447-30e6c9a6183c/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203083753-4f28b9b589d6 h1:N+0xkioACl3PNo+MquCIIOL/kSICevg340IYOFGQeOw= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203083753-4f28b9b589d6/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203150531-ef916fe2d995 h1:ZDRvnzTTNHgMm5hYmseHdEPqQ6rn/4v+P9f/JIxPaNw= -cloud.o-forge.io/core/oc-lib v0.0.0-20260203150531-ef916fe2d995/go.mod h1:T0UCxRd8w+qCVVC0NEyDiWIGC5ADwEbQ7hFcvftd4Ks= -cloud.o-forge.io/core/oc-lib v0.0.0-20260205143023-b9e7ce20b6d9 h1:NoeL4aA2/z2MEqU3YWbafz6vXkRf4DZNaYSKFpv6R2k= -cloud.o-forge.io/core/oc-lib v0.0.0-20260205143023-b9e7ce20b6d9/go.mod h1:T0UCxRd8w+qCVVC0NEyDiWIGC5ADwEbQ7hFcvftd4Ks= -cloud.o-forge.io/core/oc-lib v0.0.0-20260209113703-b9c9b6678099 h1:HczicbRtjiU51McjpDkmCsrQVs406bHybbLd+ZkqTo0= -cloud.o-forge.io/core/oc-lib v0.0.0-20260209113703-b9c9b6678099/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260212123952-403913d8cf13 h1:DNIPQ7C+7wjbj5RUx29wLxuIe/wiSOcuUMlLRIv6Fvs= -cloud.o-forge.io/core/oc-lib v0.0.0-20260212123952-403913d8cf13/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260218132556-0b41e2505e2f h1:OFuJhi23D/UNwn8Jo30HDt/Sm2Ea1ljUk6IVicYSuAQ= -cloud.o-forge.io/core/oc-lib v0.0.0-20260218132556-0b41e2505e2f/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260223083003-28713536358b h1:Tx8hvmJJvt8BYNQsKGYuyCVnQHG59dfyYGP0+NDNxVs= -cloud.o-forge.io/core/oc-lib v0.0.0-20260223083003-28713536358b/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304111813-f033182382e7 h1:3FYmZpBIEkE0UB+osjEmf98Y+Cr9Z+vGIQi53xgqfLo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304111813-f033182382e7/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304112254-6217618e6ce2 h1:JivVC15CRYWNvyTpZIB5A9uWuek4FsNyZqZBjqKLUTE= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304112254-6217618e6ce2/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304113411-3e0f369850a9 h1:pIio/xf/0YpvVmgTewVcX1Z/ugaHB/ll/5+Rp3yEkUc= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304113411-3e0f369850a9/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304114006-ae7e297622ed h1:ecX0XrRws+q/Z2D7sKuT3f7rUO+OHWzj3yWWhp3v7rs= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304114006-ae7e297622ed/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304114347-334de8ca2e8f h1:1qD7JxBhVEg4hirvEOEHAcpM/xH2IKT9bL0OwtxOpxQ= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304114347-334de8ca2e8f/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304120253-473dc6266021 h1:zjcexVGP7EnzlFRDH0DDIzuypAIiPo0MGLqwka7vKs4= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304120253-473dc6266021/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304121501-b47b51126a11 h1:e+fNy5MJTnp8Lh4e2HNAtoQvfGVIFmqKbYSOAwUzXa4= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304121501-b47b51126a11/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304123105-f1eaf497aa8a h1:skbfEiMJIlJKOgyvaOwZ8eb+PwcJOD7+WasfN/9IhAc= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304123105-f1eaf497aa8a/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304124314-5d18512f67ec h1:YHyM8+nQ2T82EF2k0eWGqfuaPVFl4vHShc3MBcqJPQ0= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304124314-5d18512f67ec/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304125143-2bfcfb5736b3 h1:MwaSiGPc7N2HXLr/hQm7LIFJIzxJlAYHUbRtooWfSFA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304125143-2bfcfb5736b3/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304125443-a426bdf655e1 h1:bvVWoPSoxVmLm1l4d/upLHTOkif1hbg5dCnEczgrwew= -cloud.o-forge.io/core/oc-lib v0.0.0-20260304125443-a426bdf655e1/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260312073634-2c9c42dd516a h1:oCkb9l/Cvn0x6iicxIydrjfCNU+UHhKuklFgfzDa174= -cloud.o-forge.io/core/oc-lib v0.0.0-20260312073634-2c9c42dd516a/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260312141150-a335c905b3a2 h1:DuB6SDThFVJVQ0iI0pZnBqtCE0uW+SNI7R7ndKixu2k= -cloud.o-forge.io/core/oc-lib v0.0.0-20260312141150-a335c905b3a2/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317090440-1ac735cef10e h1:e/oYMPAqD27l3Rd473Xny/2Ut/LZnBYXAzfQArNOmrs= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317090440-1ac735cef10e/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317121951-088b45b2cff3 h1:L2ysTiSd6FFlZWxFjUIHplElbonKxcx2T2uJ3RLEgcQ= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317121951-088b45b2cff3/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317122954-f7012e285f53 h1:YBcQnQCVmmo5JD/vADlhBdyGs79wUuUpmnd99GtXayM= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317122954-f7012e285f53/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317123636-8fd4f5faefe0 h1:D9F9Evy9ijxuhz7H9Q0gaUDzkxT87AetLd+4QYQ9gWE= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317123636-8fd4f5faefe0/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317125243-b3dbc7687e68 h1:zn2xpYJW591f8eEYFL7GjsRENwBcgrZL+1v/CY0Znfo= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317125243-b3dbc7687e68/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317130319-e79101f58d54 h1:WbkVCO41d58GoQscq4/uAx+sj4NYaSdTJHyfMyOF23E= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317130319-e79101f58d54/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317131749-0fd251327879 h1:l5nhPCSXPn6bJtViBNZsLv4cWOUJQkzmt3389BzrC0I= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317131749-0fd251327879/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317132611-333476e2c567 h1:ZI0lHrpDGS8fvtKc9AedRZgOl7sAKpJH/KjU7ynVUCI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317132611-333476e2c567/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317133239-2a2dd96870ee h1:Quv6iAj2WHdsgQygni5auEjO/OgPJDC6c6PlbY+tLF4= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317133239-2a2dd96870ee/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317133706-562dfb18c1c2 h1:myADSI2TMOfHnFqK4bZGKOkgmuuoNe1xyw6+C/ZJi00= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317133706-562dfb18c1c2/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317135413-67778e1e47f4 h1:5BcA5BYk+0FBna0o0uGOBpNz2OhobC+0gBrrv7Df934= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317135413-67778e1e47f4/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317135927-72be3118b7af h1:IySCYxJrKUpmRa2R3hXSaYxfWf/cm28NRpmwluEmzBI= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317135927-72be3118b7af/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317142554-e758144b462f h1:G8wxkp+7NPlwEPca+H2B2SW+QqUxYlTiRSApQhRnZN4= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317142554-e758144b462f/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317143125-94837f8d2407 h1:g9uvFQW3xng3IBotajMdamaYlY60M+3IeCA05a3cxJ8= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317143125-94837f8d2407/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317144927-7f8d697e4cc4 h1:RN5venI+HB2xnbA24CePTf8z0mpEkYFd7fwAqWaTZwg= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317144927-7f8d697e4cc4/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317150939-5753450965ec h1:EYdJM5SOZQCo/Ew1lOmxp2My8tBTGjrOFU9HlwmTP70= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317150939-5753450965ec/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317151512-96beaade2448 h1:PAAeEUfexpuGs02Q5qHIz+eAOIPXhYL2rX43CJhw7Tk= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317151512-96beaade2448/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317152442-0a87343e3e90 h1:K5PZAJihyjGtSirEvyJvvDVkg9BZ7zp0tWBWHGGMw/8= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317152442-0a87343e3e90/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317153535-c39bc52312f7 h1:WpIYEW3hSn6XZB2k/XYHDgUX1lFj/GhZb8U+nKTakto= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317153535-c39bc52312f7/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317154203-d0645f5ca7a5 h1:vAJfMurcxZfTwL98/yJn+NKh5d4ljn2BYCMQBnJh5dg= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317154203-d0645f5ca7a5/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317154640-cec8033ddc84 h1:Z23MadPTK88abw+YfbuorqUacDTbqjMP62OB7DVFjls= -cloud.o-forge.io/core/oc-lib v0.0.0-20260317154640-cec8033ddc84/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260318073002-85314baac33c h1:6+S8ZD4fFgC10xohqFVrR1EIkLgjulBzMFLXjMbiFNw= -cloud.o-forge.io/core/oc-lib v0.0.0-20260318073002-85314baac33c/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= -cloud.o-forge.io/core/oc-lib v0.0.0-20260318074039-6a907236faec h1:bDj1QV9bnpUMgoSUygpxkdSC0gXv+rEV/zNjPustU9I= -cloud.o-forge.io/core/oc-lib v0.0.0-20260318074039-6a907236faec/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= +cloud.o-forge.io/core/oc-lib v0.0.0-20260330082109-a4ab3285e34c h1:M0y5jI9BO7fyi1nMa2S2hhY0jDbBC+Bg56+5tp9g/vs= +cloud.o-forge.io/core/oc-lib v0.0.0-20260330082109-a4ab3285e34c/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= +cloud.o-forge.io/core/oc-lib v0.0.0-20260331181901-f3b5a54545ee h1:iJ1kgMbBOBIHwS4jHOVB5zFqOd7J9ZlweQBuchnmvT0= +cloud.o-forge.io/core/oc-lib v0.0.0-20260331181901-f3b5a54545ee/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= +cloud.o-forge.io/core/oc-lib v0.0.0-20260401110447-20cac09f9d6f h1:yyp4UIBTEQWcmoD2T+Acb6dZfl7PWaLSRPwlpEOQxnE= +cloud.o-forge.io/core/oc-lib v0.0.0-20260401110447-20cac09f9d6f/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/beego/beego/v2 v2.3.4 h1:HurQEOGIEhLlPFCTR6ZDuQkybrUl2Ag2i6CdVD2rGiI= -github.com/beego/beego/v2 v2.3.4/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -111,6 +23,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= @@ -141,6 +55,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -149,15 +65,21 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/goraz/onion v0.1.3 h1:KhyvbDA2b70gcz/d5izfwTiOH8SmrvV43AsVzpng3n0= github.com/goraz/onion v0.1.3/go.mod h1:XEmz1XoBz+wxTgWB8NwuvRm4RAu3vKxvrmYtzK+XCuQ= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -167,6 +89,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -178,6 +102,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-libp2p/core v0.43.0-rc2 h1:1X1aDJNWhMfodJ/ynbaGLkgnC8f+hfBIqQDrzxFZOqI= github.com/libp2p/go-libp2p/core v0.43.0-rc2/go.mod h1:NYeJ9lvyBv9nbDk2IuGb8gFKEOkIv/W5YRIy1pAJB2Q= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -190,6 +116,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -203,6 +131,22 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= +github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/nats.go v1.43.0 h1:uRFZ2FEoRvP64+UUhaTokyS18XBCR/xM2vQZKO4i8ug= @@ -212,6 +156,10 @@ github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVx github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= +github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= +github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -225,9 +173,7 @@ github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2 github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= @@ -241,15 +187,21 @@ github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -270,26 +222,24 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -302,8 +252,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -314,8 +262,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= @@ -324,9 +270,9 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -353,6 +299,8 @@ k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZ k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= diff --git a/infrastructure/docker_scraper.go b/infrastructure/docker_scraper.go new file mode 100644 index 0000000..84c4f8e --- /dev/null +++ b/infrastructure/docker_scraper.go @@ -0,0 +1,582 @@ +package infrastructure + +// docker_scraper.go — Seeds the catalog with official Docker Hub images as +// ProcessingResources at API startup, then refreshes on a configurable interval. +// +// Each image version (tag) becomes one *peerless* ProcessingInstance: +// - CreatorID = "" (no owning peer) +// - Partnerships = nil (no partnerships) +// - Origin.Ref = "docker.io/:" (non-empty registry ref) +// +// This satisfies ResourceInstance.IsPeerless() and makes every instance freely +// accessible to all peers without any pricing negotiation. +// +// Environment variables (all optional): +// +// DOCKER_SCRAPER_ENABLED true | false (default: true) +// DOCKER_SCRAPER_IMAGES comma-separated list of images to track. +// Format: "name" for official library images, +// "org/name" for user/org images. +// Default: a curated set of popular official images. +// DOCKER_SCRAPER_MAX_TAGS max tags to import per image (default: 10) +// DOCKER_SCRAPER_INTERVAL_H refresh interval in hours (default: 24) + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "regexp" + "strconv" + "strings" + "time" + + "cloud.o-forge.io/core/oc-lib/dbs" + "cloud.o-forge.io/core/oc-lib/models/common/enum" + "cloud.o-forge.io/core/oc-lib/models/common/models" + "cloud.o-forge.io/core/oc-lib/models/resources" + "cloud.o-forge.io/core/oc-lib/models/utils" + "cloud.o-forge.io/core/oc-lib/tools" + "github.com/google/uuid" +) + +// ─── Configuration ──────────────────────────────────────────────────────────── + +// DockerImageSpec identifies one Docker Hub repository to scrape. +// Namespace is "library" for official images, or the org/user name otherwise. +type DockerImageSpec struct { + Namespace string + Name string +} + +// scraperConfig holds all runtime parameters for the Docker Hub scraper. +type scraperConfig struct { + Enabled bool + Images []DockerImageSpec + MaxTags int + IntervalHours int +} + +// defaultImages is the baseline catalog seeded when DOCKER_SCRAPER_IMAGES is not set. +var defaultImages = []DockerImageSpec{ + {Namespace: "library", Name: "ubuntu"}, + {Namespace: "library", Name: "debian"}, + {Namespace: "library", Name: "alpine"}, + {Namespace: "library", Name: "python"}, + {Namespace: "library", Name: "golang"}, + {Namespace: "library", Name: "node"}, + {Namespace: "library", Name: "nginx"}, + {Namespace: "library", Name: "postgres"}, + {Namespace: "library", Name: "redis"}, + {Namespace: "library", Name: "mysql"}, + {Namespace: "library", Name: "redmine"}, + {Namespace: "library", Name: "ruby"}, + {Namespace: "library", Name: "rabbitmq"}, + {Namespace: "library", Name: "nextcloud"}, + {Namespace: "library", Name: "php"}, + {Namespace: "library", Name: "wordpress"}, + {Namespace: "library", Name: "fluentd"}, + {Namespace: "library", Name: "gradle"}, + {Namespace: "library", Name: "mongo"}, + {Namespace: "library", Name: "clickhouse"}, + {Namespace: "library", Name: "mariadb"}, + {Namespace: "library", Name: "eclipse-temurin"}, + {Namespace: "library", Name: "sonarqube"}, + {Namespace: "library", Name: "neo4j"}, + {Namespace: "library", Name: "rust"}, + {Namespace: "library", Name: "oraclelinux"}, + {Namespace: "library", Name: "openjdk"}, + {Namespace: "library", Name: "traefik"}, + {Namespace: "library", Name: "ghost"}, + {Namespace: "library", Name: "docker"}, + {Namespace: "library", Name: "websphere-liberty"}, + {Namespace: "library", Name: "open-liberty"}, + {Namespace: "library", Name: "storm"}, + {Namespace: "library", Name: "swift"}, + {Namespace: "library", Name: "rocket.chat"}, + {Namespace: "library", Name: "odoo"}, + {Namespace: "library", Name: "busybox"}, + {Namespace: "library", Name: "nats"}, + {Namespace: "library", Name: "mageia"}, + {Namespace: "library", Name: "tomcat"}, + {Namespace: "library", Name: "perl"}, + {Namespace: "library", Name: "xwiki"}, + {Namespace: "library", Name: "cassandra"}, + {Namespace: "library", Name: "varnish"}, + {Namespace: "library", Name: "ibm-semeru-runtimes"}, + {Namespace: "library", Name: "archlinux"}, + {Namespace: "library", Name: "clojure"}, + {Namespace: "library", Name: "maven"}, + {Namespace: "library", Name: "buildpack-deps"}, + {Namespace: "library", Name: "solr"}, + {Namespace: "library", Name: "groovy"}, + {Namespace: "library", Name: "phpmyadmin"}, + {Namespace: "library", Name: "hylang"}, + {Namespace: "library", Name: "joomla"}, + {Namespace: "library", Name: "matomo"}, + {Namespace: "library", Name: "drupal"}, + {Namespace: "library", Name: "yourls"}, + {Namespace: "library", Name: "haproxy"}, + {Namespace: "library", Name: "elixir"}, + {Namespace: "library", Name: "geonetwork"}, + {Namespace: "library", Name: "convertigo"}, + {Namespace: "library", Name: "erlang"}, + {Namespace: "library", Name: "azul-zulu"}, + {Namespace: "library", Name: "kibana"}, + {Namespace: "library", Name: "percona"}, + {Namespace: "library", Name: "logstash"}, + {Namespace: "library", Name: "elasticsearch"}, + {Namespace: "library", Name: "krakend"}, + {Namespace: "library", Name: "postfixadmin"}, + {Namespace: "library", Name: "monica"}, + {Namespace: "library", Name: "friendica"}, + {Namespace: "library", Name: "sapmachine"}, + {Namespace: "library", Name: "dart"}, + {Namespace: "library", Name: "spiped"}, + {Namespace: "library", Name: "amazoncorreto"}, + {Namespace: "library", Name: "zookeeper"}, + {Namespace: "library", Name: "julia"}, + {Namespace: "library", Name: "gcc"}, + {Namespace: "library", Name: "ibmjava"}, + {Namespace: "library", Name: "mediawiki"}, + {Namespace: "library", Name: "couchbase"}, + {Namespace: "library", Name: "jetty"}, + {Namespace: "library", Name: "sparl"}, + {Namespace: "library", Name: "tomee"}, + {Namespace: "library", Name: "kapacitor"}, + {Namespace: "library", Name: "ros"}, + {Namespace: "library", Name: "silverpeas"}, + {Namespace: "library", Name: "jruby"}, + {Namespace: "library", Name: "neurodebian"}, + {Namespace: "library", Name: "flink"}, + {Namespace: "library", Name: "pypy"}, + {Namespace: "library", Name: "orientdb"}, + {Namespace: "library", Name: "liquidbase"}, + {Namespace: "library", Name: "haxe"}, + {Namespace: "library", Name: "r-base"}, + {Namespace: "library", Name: "lighstreamer"}, + {Namespace: "library", Name: "kong"}, + {Namespace: "library", Name: "aerospike"}, + {Namespace: "library", Name: "influxdb"}, + {Namespace: "library", Name: "irssi"}, + {Namespace: "library", Name: "rakudo-star"}, + {Namespace: "library", Name: "satosa"}, + {Namespace: "library", Name: "rethinkdb"}, + {Namespace: "library", Name: "chronograf"}, + {Namespace: "library", Name: "memcached"}, + {Namespace: "library", Name: "backdrop"}, + {Namespace: "library", Name: "telegraf"}, + {Namespace: "library", Name: "httpd"}, + {Namespace: "library", Name: "haskell"}, + {Namespace: "library", Name: "emqx"}, + {Namespace: "library", Name: "swipl"}, + {Namespace: "library", Name: "couchdb"}, + {Namespace: "library", Name: "hitch"}, + {Namespace: "library", Name: "composer"}, + {Namespace: "library", Name: "adminer"}, + {Namespace: "library", Name: "amazonlinux"}, + {Namespace: "library", Name: "bash"}, + {Namespace: "library", Name: "caddy"}, + {Namespace: "library", Name: "arangodb"}, + {Namespace: "library", Name: "bonita"}, + {Namespace: "library", Name: "photon"}, + {Namespace: "library", Name: "almalinux"}, + {Namespace: "library", Name: "teamspeak"}, + {Namespace: "library", Name: "fedora"}, + {Namespace: "library", Name: "eclipse-mosquitto"}, + {Namespace: "library", Name: "registry"}, + {Namespace: "library", Name: "eggdrop"}, + {Namespace: "library", Name: "znc"}, + {Namespace: "library", Name: "api-firewall"}, + {Namespace: "library", Name: "alt"}, + {Namespace: "library", Name: "unit"}, + {Namespace: "library", Name: "clearlinux"}, + {Namespace: "library", Name: "gazebo"}, + {Namespace: "library", Name: "mongo-express"}, + {Namespace: "library", Name: "plone"}, + {Namespace: "library", Name: "cirros"}, + {Namespace: "library", Name: "mono"}, + {Namespace: "library", Name: "nats-streaming"}, + {Namespace: "library", Name: "sl"}, + {Namespace: "library", Name: "rockylinux"}, + {Namespace: "library", Name: "notary"}, + {Namespace: "library", Name: "vault"}, + {Namespace: "library", Name: "jobber"}, + {Namespace: "library", Name: "consul"}, + {Namespace: "library", Name: "php-zendserver"}, + {Namespace: "library", Name: "centos"}, + {Namespace: "library", Name: "express-gateway"}, + {Namespace: "library", Name: "clefos"}, + {Namespace: "library", Name: "adoptopenjdk"}, + {Namespace: "library", Name: "thrift"}, + {Namespace: "library", Name: "rapidoid"}, + {Namespace: "library", Name: "kaazing-gateway"}, + {Namespace: "library", Name: "nuxeo"}, + {Namespace: "library", Name: "neo4j"}, + {Namespace: "library", Name: "fsharp"}, + {Namespace: "library", Name: "sourcemage"}, + {Namespace: "library", Name: "swarm"}, + {Namespace: "library", Name: "euleros"}, + {Namespace: "library", Name: "crux"}, + {Namespace: "library", Name: "sentry"}, + {Namespace: "library", Name: "known"}, + {Namespace: "library", Name: "opensuse"}, + {Namespace: "library", Name: "owncloud"}, + {Namespace: "library", Name: "piwik"}, + {Namespace: "library", Name: "jenkins"}, + {Namespace: "library", Name: "celery"}, + {Namespace: "library", Name: "iojs"}, + {Namespace: "library", Name: "java"}, + {Namespace: "library", Name: "rails"}, + {Namespace: "library", Name: "django"}, + {Namespace: "library", Name: "glassfish"}, + {Namespace: "library", Name: "hipache"}, + {Namespace: "library", Name: "ubuntu-upstart"}, + {Namespace: "library", Name: "ubuntu-debootstrap"}, + {Namespace: "library", Name: "docker-dev"}, + {Namespace: "library", Name: "scratch"}, +} + +// scraperConfigFromEnv reads scraper configuration from environment variables +// and returns a populated scraperConfig with sensible defaults. +func scraperConfigFromEnv() scraperConfig { + cfg := scraperConfig{ + Enabled: true, + MaxTags: 10, + IntervalHours: 24, + Images: defaultImages, + } + + if v := os.Getenv("DOCKER_SCRAPER_ENABLED"); v == "false" { + cfg.Enabled = false + } + if v := os.Getenv("DOCKER_SCRAPER_MAX_TAGS"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { + cfg.MaxTags = n + } + } + if v := os.Getenv("DOCKER_SCRAPER_INTERVAL_H"); v != "" { + if h, err := strconv.Atoi(v); err == nil && h > 0 { + cfg.IntervalHours = h + } + } + if v := os.Getenv("DOCKER_SCRAPER_IMAGES"); v != "" { + var specs []DockerImageSpec + for _, raw := range strings.Split(v, ",") { + raw = strings.TrimSpace(raw) + if raw == "" { + continue + } + if parts := strings.SplitN(raw, "/", 2); len(parts) == 2 { + specs = append(specs, DockerImageSpec{Namespace: parts[0], Name: parts[1]}) + } else { + specs = append(specs, DockerImageSpec{Namespace: "library", Name: raw}) + } + } + if len(specs) > 0 { + cfg.Images = specs + } + } + return cfg +} + +// ─── Docker Hub API types ────────────────────────────────────────────────────── + +type hubRepoInfo struct { + Description string `json:"description"` + FullDescription string `json:"full_description"` +} + +type hubTagImage struct { + Architecture string `json:"architecture"` + OS string `json:"os"` + Digest string `json:"digest"` +} + +type hubTag struct { + Name string `json:"name"` + FullSize int64 `json:"full_size"` + LastUpdated string `json:"last_updated"` + Images []hubTagImage `json:"images"` +} + +type hubTagsResponse struct { + Count int `json:"count"` + Results []hubTag `json:"results"` +} + +// reMarkdownImage matches the first Markdown image in a string, e.g. ![logo](https://…) +var reMarkdownImage = regexp.MustCompile(`!\[[^\]]*\]\((https?://[^)]+)\)`) + +// extractLogoURL returns the first image URL found in a Markdown string, or "". +func extractLogoURL(markdown string) string { + if m := reMarkdownImage.FindStringSubmatch(markdown); len(m) == 2 { + return m[1] + } + return "" +} + +// fetchJSON performs a GET request to url and decodes the JSON body into out. +func fetchJSON(url string, out interface{}) error { + resp, err := http.Get(url) //nolint:noctx + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP %d for %s", resp.StatusCode, url) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + return json.Unmarshal(body, out) +} + +// ─── Entry point ────────────────────────────────────────────────────────────── + +// StartDockerScraper starts the background Docker Hub scraper goroutine. +// It runs a full scrape immediately at startup, then repeats on the configured +// interval. This function blocks forever and is designed to be called via +// `go infrastructure.StartDockerScraper()` from main(). +func StartDockerScraper() { + cfg := scraperConfigFromEnv() + if !cfg.Enabled { + fmt.Println("[docker-scraper] disabled (DOCKER_SCRAPER_ENABLED=false)") + return + } + fmt.Printf("[docker-scraper] started — images=%d maxTags=%d interval=%dh\n", + len(cfg.Images), cfg.MaxTags, cfg.IntervalHours) + + runScrape(cfg) + + ticker := time.NewTicker(time.Duration(cfg.IntervalHours) * time.Hour) + defer ticker.Stop() + for range ticker.C { + runScrape(cfg) + } +} + +// runScrape executes one full scrape cycle for all configured images. +func runScrape(cfg scraperConfig) { + fmt.Printf("[docker-scraper] cycle started at %s\n", time.Now().Format(time.RFC3339)) + for _, spec := range cfg.Images { + if err := scrapeImage(spec, cfg.MaxTags); err != nil { + fmt.Printf("[docker-scraper] %s/%s: %v\n", spec.Namespace, spec.Name, err) + } + } + fmt.Printf("[docker-scraper] cycle done at %s\n", time.Now().Format(time.RFC3339)) +} + +// ─── Per-image scraping ──────────────────────────────────────────────────────── + +// scrapeImage fetches Docker Hub metadata for one repository, then either creates +// a new ProcessingResource in the catalog or extends the existing one with any +// missing tag-instances. +func scrapeImage(spec DockerImageSpec, maxTags int) error { + // ── Fetch image metadata ────────────────────────────────────────────────── + var info hubRepoInfo + repoURL := fmt.Sprintf("https://hub.docker.com/v2/repositories/%s/%s/", + spec.Namespace, spec.Name) + if err := fetchJSON(repoURL, &info); err != nil { + return fmt.Errorf("fetch repo info: %w", err) + } + + // ── Fetch tags ──────────────────────────────────────────────────────────── + tagsURL := fmt.Sprintf( + "https://hub.docker.com/v2/repositories/%s/%s/tags?page_size=%d&ordering=last_updated", + spec.Namespace, spec.Name, maxTags) + var tagsResp hubTagsResponse + if err := fetchJSON(tagsURL, &tagsResp); err != nil { + return fmt.Errorf("fetch tags: %w", err) + } + if len(tagsResp.Results) == 0 { + return nil // nothing to upsert + } + + adminReq := &tools.APIRequest{Admin: true} + accessor := (&resources.ProcessingResource{}).GetAccessor(adminReq) + + resourceName := spec.resourceName() + existing := findProcessingResourceByName(accessor, resourceName) + + if existing == nil { + return createDockerProcessingResource(accessor, spec, resourceName, info, tagsResp.Results) + } + return syncDockerInstances(accessor, existing, spec, tagsResp.Results) +} + +// resourceName returns the canonical catalog name for a DockerImageSpec. +// Official (library) images use just the image name; others use "org/image". +func (s DockerImageSpec) resourceName() string { + if s.Namespace == "library" { + return s.Name + } + return s.Namespace + "/" + s.Name +} + +// dockerRef builds the canonical pull reference for an image+tag pair. +func dockerRef(spec DockerImageSpec, tag string) string { + if spec.Namespace == "library" { + return "docker.io/" + spec.Name + ":" + tag + } + return "docker.io/" + spec.Namespace + "/" + spec.Name + ":" + tag +} + +// ─── DB helpers ─────────────────────────────────────────────────────────────── + +// findProcessingResourceByName loads all ProcessingResources (both draft and +// published) and returns the first whose name matches exactly. +func findProcessingResourceByName(accessor utils.Accessor, name string) *resources.ProcessingResource { + filters := &dbs.Filters{ + Or: map[string][]dbs.Filter{ + "abstractresource.abstractobject.name": {{ + Operator: dbs.LIKE.String(), + Value: name, + }}, + "abstractobject.name": {{ + Operator: dbs.LIKE.String(), + Value: name, + }}, + }, + } + for _, draft := range []bool{false, true} { + results, _, _ := accessor.Search(filters, "", draft) + for _, r := range results { + if pr, ok := r.(*resources.ProcessingResource); ok && pr.GetName() == name { + return pr + } + } + } + return nil +} + +// createDockerProcessingResource stores a brand-new ProcessingResource with one +// peerless instance per Docker Hub tag, then publishes it (IsDraft = false). +func createDockerProcessingResource( + accessor utils.Accessor, + spec DockerImageSpec, + name string, + info hubRepoInfo, + tags []hubTag, +) error { + resource := &resources.ProcessingResource{ + AbstractInstanciatedResource: resources.AbstractInstanciatedResource[*resources.ProcessingInstance]{ + AbstractResource: resources.AbstractResource{ + AbstractObject: utils.AbstractObject{ + UUID: uuid.New().String(), + Name: name, + }, + Description: info.FullDescription, + ShortDescription: info.Description, + Logo: extractLogoURL(info.FullDescription), + Owners: []utils.Owner{ + {Name: "https://hub.docker.com/", Logo: "https://icones8.fr/icon/Wln8Z3PcXanx/logo-docker"}, + }, + }, + }, + Infrastructure: enum.DOCKER, + OpenSource: true, + IsService: false, + } + + for i := range tags { + resource.AddInstances(buildPeerlessInstance(spec, tags[i])) + } + + // StoreOne goes through GenericStoreOne which calls AbstractResource.StoreDraftDefault() + // setting IsDraft=true. We then publish with a raw update. + stored, _, err := accessor.StoreOne(resource) + if err != nil { + return fmt.Errorf("store %q: %w", name, err) + } + pr := stored.(*resources.ProcessingResource) + pr.IsDraft = false + if _, _, err := utils.GenericRawUpdateOne(pr, pr.GetID(), accessor); err != nil { + return fmt.Errorf("publish %q: %w", name, err) + } + fmt.Printf("[docker-scraper] created %q with %d instances\n", name, len(tags)) + return nil +} + +// syncDockerInstances adds to an existing ProcessingResource any tag-instances +// that are not yet present (identified by Origin.Ref). Already-present tags +// are left untouched to preserve any manually enriched metadata. +func syncDockerInstances( + accessor utils.Accessor, + resource *resources.ProcessingResource, + spec DockerImageSpec, + tags []hubTag, +) error { + existing := map[string]bool{} + for _, inst := range resource.Instances { + existing[inst.GetOrigin().Ref] = true + } + + added := 0 + for i := range tags { + ref := dockerRef(spec, tags[i].Name) + if existing[ref] { + continue + } + resource.AddInstances(buildPeerlessInstance(spec, tags[i])) + added++ + } + if added == 0 { + return nil + } + + if _, _, err := utils.GenericRawUpdateOne(resource, resource.GetID(), accessor); err != nil { + return fmt.Errorf("sync instances for %q: %w", resource.GetName(), err) + } + fmt.Printf("[docker-scraper] added %d new instances to %q\n", added, resource.GetName()) + return nil +} + +// ─── Instance builder ───────────────────────────────────────────────────────── + +// buildPeerlessInstance creates a ProcessingInstance that satisfies +// ResourceInstance.IsPeerless(): +// +// CreatorID = "" (zero value — no owning peer) +// Partnerships = nil (zero value — no partnerships) +// Origin.Ref != "" (set to the canonical docker pull reference) +// +// ProcessingInstance.StoreDraftDefault() enforces this invariant on write. +func buildPeerlessInstance(spec DockerImageSpec, tag hubTag) *resources.ProcessingInstance { + ref := dockerRef(spec, tag.Name) + + // Collect architecture hint from the first image manifest entry (if any). + arch := "" + if len(tag.Images) > 0 { + arch = tag.Images[0].Architecture + } + + return &resources.ProcessingInstance{ + ResourceInstance: resources.ResourceInstance[*resources.ResourcePartnerShip[*resources.ProcessingResourcePricingProfile]]{ + AbstractObject: utils.AbstractObject{ + UUID: uuid.New().String(), + Name: tag.Name, + // CreatorID intentionally left empty — required for IsPeerless() + }, + Origin: resources.OriginMeta{ + Type: resources.OriginPublic, + Ref: ref, + License: "", // filled in per-image if known (e.g. MIT, Apache-2.0) + Verified: true, // official Docker Hub images are considered verified + }, + // Env / Inputs / Outputs left empty — can be enriched manually or by + // future scrapers that read image labels / Docker Hub documentation. + }, + Access: &resources.ProcessingResourceAccess{ + Container: &models.Container{ + Image: ref, + // Command, Args, Env, Volumes left empty — image defaults apply. + Env: map[string]string{ + "ARCH": arch, + }, + }, + }, + } +} diff --git a/infrastructure/nats.go b/infrastructure/nats.go index ba76e9f..4a5fe7e 100644 --- a/infrastructure/nats.go +++ b/infrastructure/nats.go @@ -2,12 +2,13 @@ package infrastructure import ( "encoding/json" - "fmt" "slices" "sync" oclib "cloud.o-forge.io/core/oc-lib" + "cloud.o-forge.io/core/oc-lib/models/booking" "cloud.o-forge.io/core/oc-lib/models/resources" + "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/tools" ) @@ -20,14 +21,16 @@ var ressourceCols = []oclib.LibDataEnum{ } var SearchMu sync.RWMutex -var SearchStream = map[string]chan resources.ResourceInterface{} +var SearchStream = map[string]chan []byte{} +var SearchStreamSeen = map[string][]string{} func EmitNATS(user string, groups []string, message tools.PropalgationMessage) { b, _ := json.Marshal(message) switch message.Action { case tools.PB_SEARCH: SearchMu.Lock() - SearchStream[user] = make(chan resources.ResourceInterface, 128) + SearchStream[user] = make(chan []byte, 128) + SearchStreamSeen[user] = make([]string, 128) SearchMu.Unlock() tools.NewNATSCaller().SetNATSPub(tools.PROPALGATION_EVENT, tools.NATSResponse{ FromApp: "oc-catalog", @@ -65,13 +68,123 @@ func ListenNATS() { return } p, err := resources.ToResource(int(resp.Datatype), resp.Payload) - if err == nil { - fmt.Println("SearchStream", p) - SearchMu.Lock() - fmt.Println(SearchStream, resp.User) - SearchStream[resp.User] <- p // TODO when do we update it in our catalog ?* - SearchMu.Unlock() + if err != nil { + return + } + // Exclude resources already present in the local catalog + if check := oclib.NewRequestAdmin(oclib.LibDataEnum(resp.Datatype), nil).LoadOne(p.GetID()); check.Data == nil { + p.SetNotInCatalog(true) + return + } + wrapped, merr := json.Marshal(map[string]interface{}{ + "dtype": p.GetType(), + "data": p, + }) + if merr != nil { + return + } + SearchMu.Lock() + if SearchStreamSeen[resp.User] != nil && slices.Contains(SearchStreamSeen[resp.User], p.GetID()) { + SearchStream[resp.User] <- wrapped // TODO when do we update it in our catalog ? + } + if SearchStreamSeen[resp.User] == nil { + SearchStreamSeen[resp.User] = []string{} + } + SearchStreamSeen[resp.User] = append(SearchStreamSeen[resp.User], p.GetID()) + SearchMu.Unlock() + }, + + // ── WORKFLOW_STEP_DONE_EVENT ───────────────────────────────────────── + // Real-time update: one booking just completed → update its resource instance. + tools.WORKFLOW_STEP_DONE_EVENT: func(resp tools.NATSResponse) { + var evt tools.WorkflowLifecycleEvent + if err := json.Unmarshal(resp.Payload, &evt); err != nil || evt.BookingID == "" { + return + } + updateInstanceFromStep(tools.StepMetric{ + BookingID: evt.BookingID, + State: evt.State, + RealStart: evt.RealStart, + RealEnd: evt.RealEnd, + }) + }, + + // ── WORKFLOW_DONE_EVENT ────────────────────────────────────────────── + // Recap: apply all steps in case STEP_DONE events were missed while + // oc-catalog was down. Processing is idempotent (same duration wins + // when times are identical; running average converges anyway). + tools.WORKFLOW_DONE_EVENT: func(resp tools.NATSResponse) { + var evt tools.WorkflowLifecycleEvent + if err := json.Unmarshal(resp.Payload, &evt); err != nil { + return + } + for _, step := range evt.Steps { + updateInstanceFromStep(step) } }, }) } + +// updateInstanceFromStep loads the booking identified by step.BookingID, then +// updates the AverageDuration of the resource instance only if this peer owns +// the resource (creator_id == self PeerID). Idempotent: safe to call twice. +func updateInstanceFromStep(step tools.StepMetric) { + if step.RealStart == nil || step.RealEnd == nil { + return + } + actualS := step.RealEnd.Sub(*step.RealStart).Seconds() + if actualS <= 0 { + return + } + + adminReq := &tools.APIRequest{Admin: true} + + // Resolve resource info from the booking. + bkRes, _, err := booking.NewAccessor(adminReq).LoadOne(step.BookingID) + if err != nil || bkRes == nil { + return + } + bk := bkRes.(*booking.Booking) + + // Only update resources this peer owns. + self, selfErr := oclib.GetMySelf() + if selfErr != nil || self == nil { + return + } + + switch bk.ResourceType { + case tools.COMPUTE_RESOURCE, tools.LIVE_DATACENTER: + res, _, err := (&resources.ComputeResource{}).GetAccessor(adminReq).LoadOne(bk.ResourceID) + if err != nil || res == nil { + return + } + compute := res.(*resources.ComputeResource) + if compute.GetCreatorID() != self.PeerID { + return + } + for _, inst := range compute.Instances { + if inst.GetID() == bk.InstanceID { + inst.UpdateAverageDuration(actualS) + break + } + } + utils.GenericRawUpdateOne(compute, compute.GetID(), compute.GetAccessor(adminReq)) + + case tools.STORAGE_RESOURCE, tools.LIVE_STORAGE: + res, _, err := (&resources.StorageResource{}).GetAccessor(adminReq).LoadOne(bk.ResourceID) + if err != nil || res == nil { + return + } + storage := res.(*resources.StorageResource) + if storage.GetCreatorID() != self.PeerID { + return + } + for _, inst := range storage.Instances { + if inst.GetID() == bk.InstanceID { + inst.UpdateAverageDuration(actualS) + break + } + } + utils.GenericRawUpdateOne(storage, storage.GetID(), storage.GetAccessor(adminReq)) + } +} diff --git a/main.go b/main.go index af5fde6..6b69ff8 100755 --- a/main.go +++ b/main.go @@ -12,10 +12,15 @@ import ( const appname = "oc-catalog" func main() { - // Init the oc-lib - oclib.InitAPI(appname) + // Init the oc-lib — les routes WebSocket décentralisées sont déclarées ici + // car beego.Handler n'alimente pas GlobalControllerRouter. + oclib.InitAPI(appname, map[string][]string{ + "/oc/decentralized/:type/:datatype/search/:search": {"GET"}, + }) go oclib.InitNATSDecentralizedEmitter(tools.COMPUTE_RESOURCE, tools.DATA_RESOURCE, tools.PROCESSING_RESOURCE, tools.STORAGE_RESOURCE, tools.WORKFLOW_RESOURCE) go infrastructure.ListenNATS() + go infrastructure.StartDockerScraper() + beego.Run() } diff --git a/oc-catalog b/oc-catalog index 6ae441e..49d6766 100755 Binary files a/oc-catalog and b/oc-catalog differ diff --git a/routers/commentsRouter.go b/routers/commentsRouter.go index f8121da..1a9971c 100755 --- a/routers/commentsRouter.go +++ b/routers/commentsRouter.go @@ -7,114 +7,6 @@ import ( func init() { - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "Put", - Router: `/:id`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:id`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ComputeController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "Put", - Router: `/:id`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:id`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:DataController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:DataController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:EnumController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:EnumController"], beego.ControllerComments{ Method: "EnumBookingStatus", @@ -241,7 +133,7 @@ func init() { Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], + beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], beego.ControllerComments{ Method: "Post", Router: `/`, @@ -250,7 +142,7 @@ func init() { Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], + beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], beego.ControllerComments{ Method: "GetAll", Router: `/`, @@ -259,154 +151,73 @@ func init() { Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], + beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], + beego.ControllerComments{ + Method: "Get", + Router: `/:id`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], + beego.ControllerComments{ + Method: "Search", + Router: `/search/:search`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], + beego.ControllerComments{ + Method: "GetAll", + Router: `/:type`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], + beego.ControllerComments{ + Method: "Post", + Router: `/:type`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], + beego.ControllerComments{ + Method: "Get", + Router: `/:type/:id`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], beego.ControllerComments{ Method: "Put", - Router: `/:id`, + Router: `/:type/:id`, AllowHTTPMethods: []string{"put"}, MethodParams: param.Make(), Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], + beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], beego.ControllerComments{ Method: "Delete", - Router: `/:id`, + Router: `/:type/:id`, AllowHTTPMethods: []string{"delete"}, MethodParams: param.Make(), Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ProcessingController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:PurchaseController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:ResourceController"], beego.ControllerComments{ Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "Put", - Router: `/:id`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:id`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:StorageController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, + Router: `/:type/search/:search`, AllowHTTPMethods: []string{"get"}, MethodParams: param.Make(), Filters: nil, @@ -430,58 +241,4 @@ func init() { Filters: nil, Params: nil}) - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "Put", - Router: `/:id`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:id`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:id`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - - beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"] = append(beego.GlobalControllerRouter["oc-catalog/controllers:WorkflowController"], - beego.ControllerComments{ - Method: "Search", - Router: `/search/:search`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Filters: nil, - Params: nil}) - } diff --git a/routers/router.go b/routers/router.go index 84073b9..e698e63 100755 --- a/routers/router.go +++ b/routers/router.go @@ -9,6 +9,7 @@ package routers import ( "encoding/json" + "fmt" "net/http" "oc-catalog/controllers" "oc-catalog/infrastructure" @@ -17,31 +18,51 @@ import ( oclib "cloud.o-forge.io/core/oc-lib" "cloud.o-forge.io/core/oc-lib/tools" beego "github.com/beego/beego/v2/server/web" + "github.com/gorilla/websocket" ) -// wsSearchHandler retourne un http.HandlerFunc qui émet un message NATS puis ouvre la connexion WS. -// dataType == -1 signifie toutes les ressources (ResourceController). -func wsSearchHandler(dataType int) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - parts := strings.Split(strings.TrimSuffix(r.URL.Path, "/"), "/") - search := parts[len(parts)-1] - t := "" - if len(parts) >= 3 { - t = parts[len(parts)-3] - } - user, _, groups := oclib.ExtractTokenInfo(*r) - b, _ := json.Marshal(map[string]string{"search": search, "type": t}) - infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ - Action: tools.PB_SEARCH, - DataType: dataType, - Payload: b, - }) - controllers.Websocket(r.Context(), user, groups, dataType, w, r) +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +// wsTypedSearchHandler retourne un HandlerFunc WebSocket qui résout le DataType +// depuis le segment :type de l'URL (compute, data, storage, processing, workflow). +// dataType == -1 signifie toutes les ressources. +func TypedSearchHandler(w http.ResponseWriter, r *http.Request) { + fmt.Println("wsTypedSearchHandler") + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return } + parts := strings.Split(strings.TrimSuffix(r.URL.Path, "/"), "/") + search := parts[len(parts)-1] + dt := "resource" + t := "partner" + if len(parts) >= 3 { + dt = parts[len(parts)-3] + } + if len(parts) >= 4 { + t = parts[len(parts)-4] + } + // Résout le DataType depuis le slug de type (ex: "compute" → COMPUTE_RESOURCE) + dataType := tools.FromString(strings.ToLower(dt) + "_resource") + if dataType <= 0 { + dataType = -1 + } + user, _, groups := oclib.ExtractTokenInfo(*r) + b, _ := json.Marshal(map[string]string{"search": search, "type": t}) + infrastructure.EmitNATS(user, groups, tools.PropalgationMessage{ + Action: tools.PB_SEARCH, + DataType: dataType, + Payload: b, + }) + controllers.Websocket(r.Context(), user, groups, dataType, conn) } func init() { - ns := beego.NewNamespace("/oc/", + ns := beego.NewNamespace("/oc", beego.NSNamespace("/generic", beego.NSInclude( &controllers.GeneralController{}, @@ -57,31 +78,6 @@ func init() { &controllers.ResourceController{}, ), ), - beego.NSNamespace("/data", - beego.NSInclude( - &controllers.DataController{}, - ), - ), - beego.NSNamespace("/compute", - beego.NSInclude( - &controllers.ComputeController{}, - ), - ), - beego.NSNamespace("/storage", - beego.NSInclude( - &controllers.StorageController{}, - ), - ), - beego.NSNamespace("/processing", - beego.NSInclude( - &controllers.ProcessingController{}, - ), - ), - beego.NSNamespace("/workflow", - beego.NSInclude( - &controllers.WorkflowController{}, - ), - ), beego.NSNamespace("/enum", beego.NSInclude( &controllers.EnumController{}, @@ -94,12 +90,7 @@ func init() { ), ) beego.AddNamespace(ns) - - // Routes WebSocket hors du pipeline Beego (évite le WriteHeader parasite) - beego.Handler("/oc/resource/decentralized/:type/search/:search", wsSearchHandler(-1)) - beego.Handler("/oc/compute/decentralized/:type/search/:search", wsSearchHandler(tools.COMPUTE_RESOURCE.EnumIndex())) - beego.Handler("/oc/data/decentralized/:type/search/:search", wsSearchHandler(tools.DATA_RESOURCE.EnumIndex())) - beego.Handler("/oc/processing/decentralized/:type/search/:search", wsSearchHandler(tools.PROCESSING_RESOURCE.EnumIndex())) - beego.Handler("/oc/storage/decentralized/:type/search/:search", wsSearchHandler(tools.STORAGE_RESOURCE.EnumIndex())) - beego.Handler("/oc/workflow/decentralized/:type/search/:search", wsSearchHandler(tools.WORKFLOW_RESOURCE.EnumIndex())) + beego.Handler("/oc/decentralized/:type/:datatype/search/:search", http.HandlerFunc(TypedSearchHandler)) + // Route WebSocket décentralisée unique — le handler résout le type depuis l'URL. + // Hors pipeline Beego pour éviter le WriteHeader parasite. } diff --git a/swagger/swagger.json b/swagger/swagger.json index d35a028..a347305 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -13,287 +13,8 @@ "url": "https://www.gnu.org/licenses/agpl-3.0.html" } }, - "basePath": "/oc/", + "basePath": "/oc", "paths": { - "/compute/": { - "get": { - "tags": [ - "compute" - ], - "description": "find compute by id\n\u003cbr\u003e", - "operationId": "ComputeController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{compute} models.compute" - } - } - }, - "post": { - "tags": [ - "compute" - ], - "description": "create compute\n\u003cbr\u003e", - "operationId": "ComputeController.Create", - "parameters": [ - { - "in": "body", - "name": "compute", - "description": "body for compute content (Json format)", - "required": true, - "schema": { - "$ref": "#/definitions/json" - } - } - ], - "responses": { - "200": { - "description": "{compute} models.compute" - } - } - } - }, - "/compute/search/{search}": { - "get": { - "tags": [ - "compute" - ], - "description": "find compute by key word\n\u003cbr\u003e", - "operationId": "ComputeController.Get", - "parameters": [ - { - "in": "path", - "name": "search", - "description": "the search you want to get", - "required": true, - "type": "string" - }, - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{compute} models.compute" - } - } - } - }, - "/compute/{id}": { - "get": { - "tags": [ - "compute" - ], - "description": "find compute by id\n\u003cbr\u003e", - "operationId": "ComputeController.Get", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the id you want to get", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{compute} models.compute" - } - } - }, - "put": { - "tags": [ - "compute" - ], - "description": "create computes\n\u003cbr\u003e", - "operationId": "ComputeController.Update", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the compute id you want to get", - "required": true, - "type": "string" - }, - { - "in": "body", - "name": "body", - "description": "The compute content", - "required": true, - "schema": { - "$ref": "#/definitions/models.compute" - } - } - ], - "responses": { - "200": { - "description": "{compute} models.compute" - } - } - }, - "delete": { - "tags": [ - "compute" - ], - "description": "delete the compute\n\u003cbr\u003e", - "operationId": "ComputeController.Delete", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "The id you want to delete", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{compute} delete success!" - } - } - } - }, - "/data/": { - "get": { - "tags": [ - "data" - ], - "description": "find data by id\n\u003cbr\u003e", - "operationId": "DataController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{data} models.data" - } - } - }, - "post": { - "tags": [ - "data" - ], - "description": "create data\n\u003cbr\u003e", - "operationId": "DataController.Create", - "parameters": [ - { - "in": "body", - "name": "data", - "description": "body for data content (Json format)", - "required": true, - "schema": { - "$ref": "#/definitions/json" - } - } - ], - "responses": { - "200": { - "description": "{data} models.data" - } - } - } - }, - "/data/search/{search}": { - "get": { - "tags": [ - "data" - ], - "responses": { - "200": { - "description": "{data} models.data" - } - } - } - }, - "/data/{id}": { - "get": { - "tags": [ - "data" - ], - "description": "find data by id\n\u003cbr\u003e", - "operationId": "DataController.Get", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the id you want to get", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{data} models.data" - } - } - }, - "put": { - "tags": [ - "data" - ], - "description": "create datas\n\u003cbr\u003e", - "operationId": "DataController.Update", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the data id you want to get", - "required": true, - "type": "string" - }, - { - "in": "body", - "name": "body", - "description": "The data content", - "required": true, - "schema": { - "$ref": "#/definitions/models.data" - } - } - ], - "responses": { - "200": { - "description": "{data} models.data" - } - } - }, - "delete": { - "tags": [ - "data" - ], - "description": "delete the data\n\u003cbr\u003e", - "operationId": "DataController.Delete", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "The id you want to delete", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{data} delete success!" - } - } - } - }, "/enum/booking/status": { "get": { "tags": [ @@ -502,154 +223,6 @@ } } }, - "/processing/": { - "get": { - "tags": [ - "processing" - ], - "description": "find processing by id\n\u003cbr\u003e", - "operationId": "ProcessingController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{processing} models.processing" - } - } - }, - "post": { - "tags": [ - "processing" - ], - "description": "create processing\n\u003cbr\u003e", - "operationId": "ProcessingController.Create", - "parameters": [ - { - "in": "body", - "name": "processing", - "description": "body for processing content (Json format)", - "required": true, - "schema": { - "$ref": "#/definitions/json" - } - } - ], - "responses": { - "200": { - "description": "{processing} models.processing" - } - } - } - }, - "/processing/search/{search}": { - "get": { - "tags": [ - "processing" - ], - "description": "find processing by key word\n\u003cbr\u003e", - "operationId": "ProcessingController.Get", - "parameters": [ - { - "in": "path", - "name": "search", - "description": "the search you want to get", - "required": true, - "type": "string" - }, - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{processing} models.processing" - } - } - } - }, - "/processing/{id}": { - "get": { - "tags": [ - "processing" - ], - "description": "find processing by id\n\u003cbr\u003e", - "operationId": "ProcessingController.Get", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the id you want to get", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{processing} models.processing" - } - } - }, - "put": { - "tags": [ - "processing" - ], - "description": "create processings\n\u003cbr\u003e", - "operationId": "ProcessingController.Update", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the processing id you want to get", - "required": true, - "type": "string" - }, - { - "in": "body", - "name": "body", - "description": "The processing content", - "required": true, - "schema": { - "$ref": "#/definitions/models.processing" - } - } - ], - "responses": { - "200": { - "description": "{processing} models.processing" - } - } - }, - "delete": { - "tags": [ - "processing" - ], - "description": "delete the processing\n\u003cbr\u003e", - "operationId": "ProcessingController.Delete", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "The id you want to delete", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{processing} delete success!" - } - } - } - }, "/purchase/": { "get": { "tags": [ @@ -747,40 +320,18 @@ } } }, - "/resource/": { + "/resource/{type}": { "get": { "tags": [ "resource" ], - "description": "find resource by id\n\u003cbr\u003e", + "description": "list all resources across all types\n\u003cbr\u003e", "operationId": "ResourceController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{resource} models.resource" - } - } - } - }, - "/resource/search/{search}": { - "get": { - "tags": [ - "resource" - ], - "description": "find resource by key word\n\u003cbr\u003e", - "operationId": "ResourceController.Get", "parameters": [ { "in": "path", - "name": "search", - "description": "the search you want to get", + "name": "type", + "description": "the type you want to get", "required": true, "type": "string" }, @@ -796,63 +347,25 @@ "description": "{resource} models.resource" } } - } - }, - "/resource/{id}": { - "get": { - "tags": [ - "resource" - ], - "description": "find resource by id\n\u003cbr\u003e", - "operationId": "ResourceController.Get", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the id you want to get", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{resource} models.resource" - } - } - } - }, - "/storage/": { - "get": { - "tags": [ - "storage" - ], - "description": "find storage by id\n\u003cbr\u003e", - "operationId": "StorageController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{storage} models.storage" - } - } }, "post": { "tags": [ - "storage" + "resource" ], - "description": "create storage\n\u003cbr\u003e", - "operationId": "StorageController.Create", + "description": "search resources across all types\n\u003cbr\u003e", + "operationId": "ResourceController.Post", "parameters": [ + { + "in": "path", + "name": "type", + "description": "the type you want to get", + "required": true, + "type": "string" + }, { "in": "body", - "name": "storage", - "description": "body for storage content (Json format)", + "name": "data", + "description": "body for data content (Json format)", "required": true, "schema": { "$ref": "#/definitions/json" @@ -861,19 +374,26 @@ ], "responses": { "200": { - "description": "{storage} models.storage" + "description": "{resource} models.resource" } } } }, - "/storage/search/{search}": { + "/resource/{type}/search/{search}": { "get": { "tags": [ - "storage" + "resource" ], - "description": "find storage by key word\n\u003cbr\u003e", - "operationId": "StorageController.Get", + "description": "search resources across all types\n\u003cbr\u003e", + "operationId": "ResourceController.Search", "parameters": [ + { + "in": "path", + "name": "type", + "description": "the type you want to get", + "required": true, + "type": "string" + }, { "in": "path", "name": "search", @@ -890,81 +410,114 @@ ], "responses": { "200": { - "description": "{storage} models.storage" + "description": "{resource} models.resource" } } } }, - "/storage/{id}": { + "/resource/{type}/{id}": { "get": { "tags": [ - "storage" + "resource" ], - "description": "find storage by id\n\u003cbr\u003e", - "operationId": "StorageController.Get", + "description": "search resources across all types\n\u003cbr\u003e", + "operationId": "ResourceController.Get", "parameters": [ + { + "in": "path", + "name": "type", + "description": "the type you want to get", + "required": true, + "type": "string" + }, { "in": "path", "name": "id", "description": "the id you want to get", "required": true, "type": "string" + }, + { + "in": "query", + "name": "is_draft", + "description": "draft wished", + "type": "string" } ], "responses": { "200": { - "description": "{storage} models.storage" + "description": "{resource} models.resource" } } }, "put": { "tags": [ - "storage" + "resource" ], - "description": "create storages\n\u003cbr\u003e", - "operationId": "StorageController.Update", + "description": "search resources across all types\n\u003cbr\u003e", + "operationId": "ResourceController.Put", "parameters": [ + { + "in": "path", + "name": "type", + "description": "the type you want to get", + "required": true, + "type": "string" + }, { "in": "path", "name": "id", - "description": "the storage id you want to get", + "description": "the id you want to get", "required": true, "type": "string" }, { "in": "body", - "name": "body", - "description": "The storage content", + "name": "data", + "description": "body for data content (Json format)", "required": true, "schema": { - "$ref": "#/definitions/models.storage" + "$ref": "#/definitions/json" } } ], "responses": { "200": { - "description": "{storage} models.storage" + "description": "{resource} models.resource" } } }, "delete": { "tags": [ - "storage" + "resource" ], - "description": "delete the storage\n\u003cbr\u003e", - "operationId": "StorageController.Delete", + "description": "search resources across all types\n\u003cbr\u003e", + "operationId": "ResourceController.Delete", "parameters": [ { "in": "path", - "name": "id", - "description": "The id you want to delete", + "name": "type", + "description": "the type you want to get", "required": true, "type": "string" + }, + { + "in": "path", + "name": "id", + "description": "the id you want to get", + "required": true, + "type": "string" + }, + { + "in": "query", + "name": "is_draft", + "description": "draft wished", + "type": "string" } ], "responses": { "200": { - "description": "{storage} delete success!" + "description": "{resource} models.resource" } } } @@ -996,180 +549,12 @@ } } } - }, - "/workflow/": { - "get": { - "tags": [ - "workflow" - ], - "description": "find workflow by id\n\u003cbr\u003e", - "operationId": "WorkflowController.GetAll", - "parameters": [ - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{workflow} models.workflow" - } - } - }, - "post": { - "tags": [ - "workflow" - ], - "description": "create workflow\n\u003cbr\u003e", - "operationId": "WorkflowController.Create", - "parameters": [ - { - "in": "body", - "name": "workflow", - "description": "body for workflow content (Json format)", - "required": true, - "schema": { - "$ref": "#/definitions/json" - } - } - ], - "responses": { - "200": { - "description": "{workflow} models.workflow" - } - } - } - }, - "/workflow/search/{search}": { - "get": { - "tags": [ - "workflow" - ], - "description": "find workflow by key word\n\u003cbr\u003e", - "operationId": "WorkflowController.Search", - "parameters": [ - { - "in": "path", - "name": "search", - "description": "the search you want to get", - "required": true, - "type": "string" - }, - { - "in": "query", - "name": "is_draft", - "description": "draft wished", - "type": "string" - } - ], - "responses": { - "200": { - "description": "{workflow} models.workflow" - } - } - } - }, - "/workflow/{id}": { - "get": { - "tags": [ - "workflow" - ], - "description": "find workflow by id\n\u003cbr\u003e", - "operationId": "WorkflowController.Get", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the id you want to get", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{workflow} models.workflow" - } - } - }, - "put": { - "tags": [ - "workflow" - ], - "description": "create workflows\n\u003cbr\u003e", - "operationId": "WorkflowController.Update", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "the workflow id you want to get", - "required": true, - "type": "string" - }, - { - "in": "body", - "name": "body", - "description": "The workflow content", - "required": true, - "schema": { - "$ref": "#/definitions/models.workflow" - } - } - ], - "responses": { - "200": { - "description": "{workflow} models.workflow" - } - } - }, - "delete": { - "tags": [ - "workflow" - ], - "description": "delete the workflow\n\u003cbr\u003e", - "operationId": "WorkflowController.Delete", - "parameters": [ - { - "in": "path", - "name": "id", - "description": "The id you want to delete", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "{workflow} delete success!" - } - } - } } }, "definitions": { "json": { "title": "json", "type": "object" - }, - "models.compute": { - "title": "compute", - "type": "object" - }, - "models.data": { - "title": "data", - "type": "object" - }, - "models.processing": { - "title": "processing", - "type": "object" - }, - "models.storage": { - "title": "storage", - "type": "object" - }, - "models.workflow": { - "title": "workflow", - "type": "object" } }, "tags": [ @@ -1183,27 +568,7 @@ }, { "name": "resource", - "description": "Operations about resource\n" - }, - { - "name": "data", - "description": "Operations about data\n" - }, - { - "name": "compute", - "description": "Operations about compute\n" - }, - { - "name": "storage", - "description": "Operations about storage\n" - }, - { - "name": "processing", - "description": "Operations about processing\n" - }, - { - "name": "workflow", - "description": "Operations about workflow\n" + "description": "ResourceController aggregates all resource types.\n" }, { "name": "enum", diff --git a/swagger/swagger.yml b/swagger/swagger.yml index eadf64c..7be3417 100644 --- a/swagger/swagger.yml +++ b/swagger/swagger.yml @@ -10,212 +10,8 @@ info: license: name: AGPL url: https://www.gnu.org/licenses/agpl-3.0.html -basePath: /oc/ +basePath: /oc paths: - /compute/: - get: - tags: - - compute - description: |- - find compute by id -
- operationId: ComputeController.GetAll - parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{compute} models.compute' - post: - tags: - - compute - description: |- - create compute -
- operationId: ComputeController.Create - parameters: - - in: body - name: compute - description: body for compute content (Json format) - required: true - schema: - $ref: '#/definitions/json' - responses: - "200": - description: '{compute} models.compute' - /compute/{id}: - get: - tags: - - compute - description: |- - find compute by id -
- operationId: ComputeController.Get - parameters: - - in: path - name: id - description: the id you want to get - required: true - type: string - responses: - "200": - description: '{compute} models.compute' - put: - tags: - - compute - description: |- - create computes -
- operationId: ComputeController.Update - parameters: - - in: path - name: id - description: the compute id you want to get - required: true - type: string - - in: body - name: body - description: The compute content - required: true - schema: - $ref: '#/definitions/models.compute' - responses: - "200": - description: '{compute} models.compute' - delete: - tags: - - compute - description: |- - delete the compute -
- operationId: ComputeController.Delete - parameters: - - in: path - name: id - description: The id you want to delete - required: true - type: string - responses: - "200": - description: '{compute} delete success!' - /compute/search/{search}: - get: - tags: - - compute - description: |- - find compute by key word -
- operationId: ComputeController.Get - parameters: - - in: path - name: search - description: the search you want to get - required: true - type: string - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{compute} models.compute' - /data/: - get: - tags: - - data - description: |- - find data by id -
- operationId: DataController.GetAll - parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{data} models.data' - post: - tags: - - data - description: |- - create data -
- operationId: DataController.Create - parameters: - - in: body - name: data - description: body for data content (Json format) - required: true - schema: - $ref: '#/definitions/json' - responses: - "200": - description: '{data} models.data' - /data/{id}: - get: - tags: - - data - description: |- - find data by id -
- operationId: DataController.Get - parameters: - - in: path - name: id - description: the id you want to get - required: true - type: string - responses: - "200": - description: '{data} models.data' - put: - tags: - - data - description: |- - create datas -
- operationId: DataController.Update - parameters: - - in: path - name: id - description: the data id you want to get - required: true - type: string - - in: body - name: body - description: The data content - required: true - schema: - $ref: '#/definitions/models.data' - responses: - "200": - description: '{data} models.data' - delete: - tags: - - data - description: |- - delete the data -
- operationId: DataController.Delete - parameters: - - in: path - name: id - description: The id you want to delete - required: true - type: string - responses: - "200": - description: '{data} delete success!' - /data/search/{search}: - get: - tags: - - data - responses: - "200": - description: '{data} models.data' /enum/booking/status: get: tags: @@ -378,115 +174,6 @@ paths: description: '{compute} models.workflow' "406": description: '{string} string "Bad request"' - /processing/: - get: - tags: - - processing - description: |- - find processing by id -
- operationId: ProcessingController.GetAll - parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{processing} models.processing' - post: - tags: - - processing - description: |- - create processing -
- operationId: ProcessingController.Create - parameters: - - in: body - name: processing - description: body for processing content (Json format) - required: true - schema: - $ref: '#/definitions/json' - responses: - "200": - description: '{processing} models.processing' - /processing/{id}: - get: - tags: - - processing - description: |- - find processing by id -
- operationId: ProcessingController.Get - parameters: - - in: path - name: id - description: the id you want to get - required: true - type: string - responses: - "200": - description: '{processing} models.processing' - put: - tags: - - processing - description: |- - create processings -
- operationId: ProcessingController.Update - parameters: - - in: path - name: id - description: the processing id you want to get - required: true - type: string - - in: body - name: body - description: The processing content - required: true - schema: - $ref: '#/definitions/models.processing' - responses: - "200": - description: '{processing} models.processing' - delete: - tags: - - processing - description: |- - delete the processing -
- operationId: ProcessingController.Delete - parameters: - - in: path - name: id - description: The id you want to delete - required: true - type: string - responses: - "200": - description: '{processing} delete success!' - /processing/search/{search}: - get: - tags: - - processing - description: |- - find processing by key word -
- operationId: ProcessingController.Get - parameters: - - in: path - name: search - description: the search you want to get - required: true - type: string - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{processing} models.processing' /purchase/: get: tags: @@ -558,51 +245,18 @@ paths: responses: "200": description: '{compute} models.compute' - /resource/: + /resource/{type}: get: tags: - resource description: |- - find resource by id + list all resources across all types
operationId: ResourceController.GetAll parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{resource} models.resource' - /resource/{id}: - get: - tags: - - resource - description: |- - find resource by id -
- operationId: ResourceController.Get - parameters: - in: path - name: id - description: the id you want to get - required: true - type: string - responses: - "200": - description: '{resource} models.resource' - /resource/search/{search}: - get: - tags: - - resource - description: |- - find resource by key word -
- operationId: ResourceController.Get - parameters: - - in: path - name: search - description: the search you want to get + name: type + description: the type you want to get required: true type: string - in: query @@ -612,103 +266,120 @@ paths: responses: "200": description: '{resource} models.resource' - /storage/: - get: - tags: - - storage - description: |- - find storage by id -
- operationId: StorageController.GetAll - parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{storage} models.storage' post: tags: - - storage + - resource description: |- - create storage + search resources across all types
- operationId: StorageController.Create + operationId: ResourceController.Post parameters: + - in: path + name: type + description: the type you want to get + required: true + type: string - in: body - name: storage - description: body for storage content (Json format) + name: data + description: body for data content (Json format) required: true schema: $ref: '#/definitions/json' responses: "200": - description: '{storage} models.storage' - /storage/{id}: + description: '{resource} models.resource' + /resource/{type}/{id}: get: tags: - - storage + - resource description: |- - find storage by id + search resources across all types
- operationId: StorageController.Get + operationId: ResourceController.Get parameters: + - in: path + name: type + description: the type you want to get + required: true + type: string - in: path name: id description: the id you want to get required: true type: string + - in: query + name: is_draft + description: draft wished + type: string responses: "200": - description: '{storage} models.storage' + description: '{resource} models.resource' put: tags: - - storage + - resource description: |- - create storages + search resources across all types
- operationId: StorageController.Update + operationId: ResourceController.Put parameters: + - in: path + name: type + description: the type you want to get + required: true + type: string - in: path name: id - description: the storage id you want to get + description: the id you want to get required: true type: string - in: body - name: body - description: The storage content + name: data + description: body for data content (Json format) required: true schema: - $ref: '#/definitions/models.storage' + $ref: '#/definitions/json' responses: "200": - description: '{storage} models.storage' + description: '{resource} models.resource' delete: tags: - - storage + - resource description: |- - delete the storage + search resources across all types
- operationId: StorageController.Delete + operationId: ResourceController.Delete parameters: - in: path - name: id - description: The id you want to delete + name: type + description: the type you want to get required: true type: string + - in: path + name: id + description: the id you want to get + required: true + type: string + - in: query + name: is_draft + description: draft wished + type: string responses: "200": - description: '{storage} delete success!' - /storage/search/{search}: + description: '{resource} models.resource' + /resource/{type}/search/{search}: get: tags: - - storage + - resource description: |- - find storage by key word + search resources across all types
- operationId: StorageController.Get + operationId: ResourceController.Search parameters: + - in: path + name: type + description: the type you want to get + required: true + type: string - in: path name: search description: the search you want to get @@ -720,7 +391,7 @@ paths: type: string responses: "200": - description: '{storage} models.storage' + description: '{resource} models.resource' /version/: get: tags: @@ -743,134 +414,10 @@ paths: responses: "200": description: "" - /workflow/: - get: - tags: - - workflow - description: |- - find workflow by id -
- operationId: WorkflowController.GetAll - parameters: - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{workflow} models.workflow' - post: - tags: - - workflow - description: |- - create workflow -
- operationId: WorkflowController.Create - parameters: - - in: body - name: workflow - description: body for workflow content (Json format) - required: true - schema: - $ref: '#/definitions/json' - responses: - "200": - description: '{workflow} models.workflow' - /workflow/{id}: - get: - tags: - - workflow - description: |- - find workflow by id -
- operationId: WorkflowController.Get - parameters: - - in: path - name: id - description: the id you want to get - required: true - type: string - responses: - "200": - description: '{workflow} models.workflow' - put: - tags: - - workflow - description: |- - create workflows -
- operationId: WorkflowController.Update - parameters: - - in: path - name: id - description: the workflow id you want to get - required: true - type: string - - in: body - name: body - description: The workflow content - required: true - schema: - $ref: '#/definitions/models.workflow' - responses: - "200": - description: '{workflow} models.workflow' - delete: - tags: - - workflow - description: |- - delete the workflow -
- operationId: WorkflowController.Delete - parameters: - - in: path - name: id - description: The id you want to delete - required: true - type: string - responses: - "200": - description: '{workflow} delete success!' - /workflow/search/{search}: - get: - tags: - - workflow - description: |- - find workflow by key word -
- operationId: WorkflowController.Search - parameters: - - in: path - name: search - description: the search you want to get - required: true - type: string - - in: query - name: is_draft - description: draft wished - type: string - responses: - "200": - description: '{workflow} models.workflow' definitions: json: title: json type: object - models.compute: - title: compute - type: object - models.data: - title: data - type: object - models.processing: - title: processing - type: object - models.storage: - title: storage - type: object - models.workflow: - title: workflow - type: object tags: - name: generic description: | @@ -880,22 +427,7 @@ tags: Operations about compute - name: resource description: | - Operations about resource -- name: data - description: | - Operations about data -- name: compute - description: | - Operations about compute -- name: storage - description: | - Operations about storage -- name: processing - description: | - Operations about processing -- name: workflow - description: | - Operations about workflow + ResourceController aggregates all resource types. - name: enum description: | Operations about resource diff --git a/ws.go b/ws.go index 2cfadda..f0ede93 100644 --- a/ws.go +++ b/ws.go @@ -26,7 +26,7 @@ func main() { // ws://localhost:8087/oc/processing/decentralized/all/search/ // ws://localhost:8087/oc/storage/decentralized/all/search/ // ws://localhost:8087/oc/workflow/decentralized/all/search/ - url := "ws://localhost:8087/oc/resource/decentralized/all/search/builder" + url := "ws://localhost:8087/oc/decentralized/all/resource/search/sar" token := "" if len(args) >= 1 { @@ -43,7 +43,6 @@ func main() { } if token != "" { config.Header.Set("Authorization", "Bearer "+token) - fmt.Printf("Token : %s...\n", token[:min(20, len(token))]) } fmt.Printf("Connexion à : %s\n", url) @@ -89,10 +88,10 @@ func main() { idleTimer.Reset(time.Duration(*timeout) * time.Second) var data any if err := json.Unmarshal([]byte(raw), &data); err == nil { - b, _ := json.MarshalIndent(data, "", " ") - fmt.Println(string(b)) + ///b, _ := json.MarshalIndent(data, "", " ") + fmt.Println(data) } else { - fmt.Printf("Message brut : %s\n", raw) + fmt.Printf("Message brut : %s\n", raw, err) } } }