Files
oc-workspace/controllers/workspace.go
T
2026-06-22 07:41:32 +02:00

214 lines
8.6 KiB
Go
Executable File

package controllers
import (
"encoding/json"
"fmt"
"strconv"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/models/workspace"
"cloud.o-forge.io/core/oc-lib/tools"
"oc-workspace/infrastructure"
beego "github.com/beego/beego/v2/server/web"
)
// Operations about workspace
type WorkspaceController struct {
beego.Controller
}
var paths = map[tools.DataType]map[tools.METHOD]string{
tools.PEER: { // paths to call to status of peers
tools.POST: "/status/",
},
tools.WORKSPACE: { // paths to call to delete/update workspace on peer destination
tools.PUT: "/:id?is_remote=true",
tools.DELETE: "/:id?is_remote=true",
},
}
// @Title Search
// @Description search workspace
// @Param search path string true "the word search you want to get"
// @Param is_draft query string false "draft wished"
// @Param offset query string false "offset wished"
// @Param limit query string false "limit wished"
// @Success 200 {workspace} models.workspace
// @router /search/:search [get]
func (o *WorkspaceController) Search() {
// user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
// store and return Id or post with UUID
search := o.Ctx.Input.Param(":search")
isDraft := o.Ctx.Input.Query("is_draft")
offset, _ := strconv.Atoi(o.Ctx.Input.Query("offset"))
limit, _ := strconv.Atoi(o.Ctx.Input.Query("limit"))
// o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.WORKSPACE), user, peerID, groups, nil).Search(nil, search, isDraft == "true")
o.Data["json"] = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), nil).Search(nil, search, isDraft == "true", int64(offset), int64(limit))
o.ServeJSON()
}
// @Title Update
// @Description create workspaces
// @Param id path string true "the workspace id you want to get"
// @Param body body models.workspace true "The workspace content"
// @Success 200 {workspace} models.workspace
// @router /:id [put]
func (o *WorkspaceController) Put() {
caller := tools.NewHTTPCaller(paths)
caller.Disabled = oclib.IsQueryParamsEquals(o.Ctx.Input, "is_remote", true)
var res map[string]interface{}
id := o.Ctx.Input.Param(":id")
json.Unmarshal(o.Ctx.Input.CopyBody(2000000), &res)
// Snapshot resource IDs before the update to detect additions and removals.
oldResources := loadWorkspaceResourceMap(id)
o.Data["json"] = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), caller).UpdateOne(res, id)
// Emit watch/unwatch events for resources that changed in this workspace.
go diffAndEmitWatchers(oldResources, extractResourceMap(res))
o.ServeJSON()
}
// resourceEntry holds the resource ID and its creator's libp2p PeerID.
type resourceEntry struct {
creatorPeerID string
dataType tools.DataType
}
// loadWorkspaceResourceMap returns the current resourceID→entry map for a workspace.
func loadWorkspaceResourceMap(id string) map[string]resourceEntry {
result := map[string]resourceEntry{}
data := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), nil).LoadOne(id)
if data.Data == nil {
return result
}
w, ok := data.Data.(*workspace.Workspace)
if !ok {
return result
}
for _, r := range w.DataResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.DATA_RESOURCE} }
for _, r := range w.ComputeResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.COMPUTE_RESOURCE} }
for _, r := range w.StorageResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.STORAGE_RESOURCE} }
for _, r := range w.ProcessingResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.PROCESSING_RESOURCE} }
for _, r := range w.WorkflowResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.WORKFLOW_RESOURCE} }
for _, r := range w.ServiceResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.SERVICE_RESOURCE} }
for _, r := range w.DynamicResources { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.DYNAMIC_RESOURCE} }
for _, r := range w.NativeTools { result[r.GetID()] = resourceEntry{creatorPeerID: r.GetCreatorID(), dataType: tools.NATIVE_TOOL} }
return result
}
// extractResourceMap parses the PUT body to build a resourceID→entry map.
// creator_id is at the top level of each resource object (from Flutter toJSON()).
var resourceArrayKeys = map[string]tools.DataType{
"data_resources": tools.DATA_RESOURCE,
"compute_resources": tools.COMPUTE_RESOURCE,
"storage_resources": tools.STORAGE_RESOURCE,
"processing_resources": tools.PROCESSING_RESOURCE,
"workflow_resources": tools.WORKFLOW_RESOURCE,
"service_resources": tools.SERVICE_RESOURCE,
"dynamic_resources": tools.DYNAMIC_RESOURCE,
"native_tools": tools.NATIVE_TOOL,
}
func extractResourceMap(body map[string]interface{}) map[string]resourceEntry {
result := map[string]resourceEntry{}
for key, dt := range resourceArrayKeys {
arr, ok := body[key].([]interface{})
if !ok {
continue
}
for _, rawR := range arr {
r, ok := rawR.(map[string]interface{})
if !ok {
continue
}
id, _ := r["id"].(string)
creatorID, _ := r["creator_id"].(string)
if id != "" {
result[id] = resourceEntry{creatorPeerID: creatorID, dataType: dt}
}
}
}
return result
}
// diffAndEmitWatchers emits PB_WATCH_RESOURCE for added non-self resources
// and PB_UNWATCH_RESOURCE for removed ones.
func diffAndEmitWatchers(old, new map[string]resourceEntry) {
for id, entry := range new {
if _, existed := old[id]; !existed {
infrastructure.EmitWatchResource(id, entry.creatorPeerID, entry.dataType)
}
}
for id, entry := range old {
if _, stillPresent := new[id]; !stillPresent {
infrastructure.EmitUnwatchResource(id, entry.creatorPeerID, entry.dataType)
}
}
}
// @Title Create
// @Description create workspace
// @Param data body json true "body for data content (Json format)"
// @Success 200 {workspace} models.workspace
// @router / [post]
func (o *WorkspaceController) Post() {
// user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
caller := tools.NewHTTPCaller(paths) // generate a http caller to send to peer shared workspace
caller.Disabled = oclib.IsQueryParamsEquals(o.Ctx.Input, "is_remote", true)
var res map[string]interface{}
json.Unmarshal(o.Ctx.Input.CopyBody(10000), &res)
// o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.WORKSPACE), user, peerID, groups, caller).StoreOne(res)
o.Data["json"] = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), caller).StoreOne(res)
o.ServeJSON()
}
// @Title GetAll
// @Description find workspace by id
// @Param is_draft query string false "draft wished"
// @Param offset query string false "offset wished"
// @Param limit query string false "limit wished"
// @Success 200 {workspace} models.workspace
// @router / [get]
func (o *WorkspaceController) GetAll() {
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
fmt.Println(user, peerID, groups)
isDraft := o.Ctx.Input.Query("is_draft")
// o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.WORKSPACE), user, peerID, groups, nil).LoadAll(isDraft == "true")
offset, _ := strconv.Atoi(o.Ctx.Input.Query("offset"))
limit, _ := strconv.Atoi(o.Ctx.Input.Query("limit"))
o.Data["json"] = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), nil).LoadAll(isDraft == "true", int64(offset), int64(limit))
o.ServeJSON()
}
// @Title Get
// @Description find workflow by idisDraft := o.Ctx.Input.Query("is_draft")
// @Param id path string true "the id you want to get"
// @Success 200 {workspace} models.workspace
// @router /:id [get]
func (o *WorkspaceController) Get() {
//user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
// o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.WORKSPACE), user, peerID, groups, nil).LoadOne(id)
o.Data["json"] = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKSPACE), nil).LoadOne(id)
o.ServeJSON()
}
// @Title Delete
// @Description delete the workspace
// @Param id path string true "The id you want to delete"
// @Success 200 {workspace} delete success!
// @router /:id [delete]
func (o *WorkspaceController) Delete() {
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
id := o.Ctx.Input.Param(":id")
caller := tools.NewHTTPCaller(paths) // generate a http caller to send to peer shared workspace
caller.Disabled = oclib.IsQueryParamsEquals(o.Ctx.Input, "is_remote", true)
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.WORKSPACE), user, peerID, groups, caller).DeleteOne(id)
o.ServeJSON()
}