package controllers import ( "encoding/json" "io" "net/http" "nodemaster/models" "time" beego "github.com/beego/beego/v2/server/web" ) // NodesController manages the registry of remote nodes. type NodesController struct { beego.Controller } // @Title GetAllNodes // @Description list all registered remote nodes // @Success 200 {object} []models.RemoteNode // @router / [get] func (c *NodesController) GetAll() { c.Data["json"] = models.GetAllRemoteNodes() c.ServeJSON() } // @Title AddNode // @Description register a remote node // @Param body body models.RemoteNode true "node to register" // @Success 201 {object} models.RemoteNode // @Failure 400 invalid body // @router / [post] func (c *NodesController) Post() { var n models.RemoteNode if err := json.Unmarshal(c.Ctx.Input.RequestBody, &n); err != nil { c.Ctx.Output.SetStatus(400) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } created, err := models.AddRemoteNode(n) if err != nil { c.Ctx.Output.SetStatus(500) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } c.Ctx.Output.SetStatus(201) c.Data["json"] = created c.ServeJSON() } // @Title GetNode // @Description get a remote node by id // @Param id path string true "node id" // @Success 200 {object} models.RemoteNode // @Failure 404 not found // @router /:id [get] func (c *NodesController) Get() { id := c.Ctx.Input.Param(":id") n, err := models.GetRemoteNode(id) if err != nil { c.Ctx.Output.SetStatus(404) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } c.Data["json"] = n c.ServeJSON() } // @Title UpdateNode // @Description update a remote node // @Param id path string true "node id" // @Param body body models.RemoteNode true "updated node data" // @Success 200 {object} models.RemoteNode // @Failure 400 invalid body // @Failure 404 not found // @router /:id [put] func (c *NodesController) Put() { id := c.Ctx.Input.Param(":id") var n models.RemoteNode if err := json.Unmarshal(c.Ctx.Input.RequestBody, &n); err != nil { c.Ctx.Output.SetStatus(400) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } updated, err := models.UpdateRemoteNode(id, n) if err != nil { c.Ctx.Output.SetStatus(404) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } c.Data["json"] = updated c.ServeJSON() } // @Title DeleteNode // @Description delete a remote node // @Param id path string true "node id" // @Success 200 {string} delete success // @Failure 404 not found // @router /:id [delete] func (c *NodesController) Delete() { id := c.Ctx.Input.Param(":id") if err := models.DeleteRemoteNode(id); err != nil { c.Ctx.Output.SetStatus(404) c.Data["json"] = map[string]string{"error": err.Error()} c.ServeJSON() return } c.Data["json"] = map[string]string{"message": "delete success"} c.ServeJSON() } type nodeServices struct { Node models.RemoteNode `json:"node"` Services []models.Service `json:"services"` Error string `json:"error,omitempty"` } // @Title GetAggregated // @Description query all registered nodes for their services and return an aggregated view // @Success 200 {object} []nodeServices // @router /aggregated [get] func (c *NodesController) GetAggregated() { nodes := models.GetAllRemoteNodes() client := &http.Client{Timeout: 10 * time.Second} results := make([]nodeServices, 0, len(nodes)) for _, node := range nodes { entry := nodeServices{Node: node} resp, err := client.Get(node.URL + "/v1/services") if err != nil { entry.Error = err.Error() results = append(results, entry) continue } body, err := io.ReadAll(resp.Body) resp.Body.Close() if err != nil { entry.Error = err.Error() results = append(results, entry) continue } var svcs []models.Service if err := json.Unmarshal(body, &svcs); err != nil { entry.Error = "failed to parse services: " + err.Error() } else { entry.Services = svcs } results = append(results, entry) } c.Data["json"] = results c.ServeJSON() }