407 lines
11 KiB
Go
407 lines
11 KiB
Go
package robot
|
|
|
|
import (
|
|
"jannex/robot-control-manager/modules/cache"
|
|
"jannex/robot-control-manager/modules/database"
|
|
"jannex/robot-control-manager/modules/logger"
|
|
"jannex/robot-control-manager/modules/robot"
|
|
"jannex/robot-control-manager/modules/structs"
|
|
"jannex/robot-control-manager/modules/utils"
|
|
"time"
|
|
|
|
"git.ex.umbach.dev/Alex/roese-utils/rslogger"
|
|
"git.ex.umbach.dev/Alex/roese-utils/rspagination"
|
|
"git.ex.umbach.dev/Alex/roese-utils/rsutils"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func FirstRequest(c *fiber.Ctx) error {
|
|
// swagger:operation POST /robot robot robotFirstRequest
|
|
// ---
|
|
// summary: First request from robot.
|
|
// description: |
|
|
// This is the first request from the robot. It will be used to identify the robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: body
|
|
// name: body
|
|
// description: First request body.
|
|
// required: true
|
|
// schema:
|
|
// "$ref": "#/definitions/FirstRequestBody"
|
|
// responses:
|
|
// "200":
|
|
// description: Robot identified
|
|
// schema:
|
|
// "$ref": "#/definitions/StatusResponse"
|
|
// "400":
|
|
// description: Invalid request body
|
|
// "403":
|
|
// description: Permit join is enabled
|
|
|
|
var body structs.FirstRequestBody
|
|
|
|
if err := rsutils.BodyParserHelper(c, &body); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
var foundRobot structs.Robot
|
|
|
|
database.DB.First(&foundRobot, "id = ?", body.Id)
|
|
|
|
if !cache.IsPermitJoinEnabled() && foundRobot.Id == "" {
|
|
logger.AddSystemLog(rslogger.LogTypeWarning, "Unauthorized robot tried to connect with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type))
|
|
return c.SendStatus(fiber.StatusForbidden)
|
|
}
|
|
|
|
if foundRobot.Id == "" {
|
|
now := time.Now()
|
|
|
|
newUnauthorizedRobot := structs.UnauthorizedRobot{
|
|
Id: body.Id,
|
|
Type: body.Type,
|
|
Address: c.IP(),
|
|
FirmwareVersion: body.FirmwareVersion,
|
|
ConnectedAt: now,
|
|
CreatedAt: now,
|
|
}
|
|
|
|
cache.AddUnauthorizedRobot(&newUnauthorizedRobot)
|
|
|
|
totalPages := cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages
|
|
|
|
robot.BroadcastSSEMessage(structs.SSEMessage{
|
|
Cmd: utils.SSESentCmdAddUnauthorizedRobot,
|
|
Body: struct {
|
|
UnauthorizedRobot *structs.UnauthorizedRobot
|
|
TotalPages int
|
|
}{
|
|
UnauthorizedRobot: &newUnauthorizedRobot,
|
|
TotalPages: totalPages,
|
|
},
|
|
})
|
|
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Unauthorized robot connected with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type))
|
|
} else {
|
|
newRobot := structs.Robot{
|
|
Id: body.Id,
|
|
Type: body.Type,
|
|
Name: foundRobot.Name,
|
|
Status: utils.RobotStatusIdle,
|
|
Address: c.IP(),
|
|
CurrentJobId: "",
|
|
FirmwareVersion: body.FirmwareVersion,
|
|
ConnectedAt: time.Now(),
|
|
CreatedAt: foundRobot.CreatedAt,
|
|
}
|
|
|
|
cache.AddRobot(&newRobot)
|
|
|
|
database.DB.Model(&structs.Robot{}).
|
|
Where("id = ?", newRobot.Id).
|
|
Updates(structs.Robot{
|
|
Status: newRobot.Status,
|
|
Type: newRobot.Type,
|
|
Address: newRobot.Address,
|
|
FirmwareVersion: newRobot.FirmwareVersion,
|
|
})
|
|
|
|
addRobotSSEMessage(&newRobot)
|
|
|
|
logger.AddRobotLog(rslogger.LogTypeInfo, newRobot.Type, newRobot.Id, "Robot connected")
|
|
}
|
|
|
|
return c.JSON(structs.StatusResponse{Status: utils.ResponseStatusOk})
|
|
}
|
|
|
|
func addRobotSSEMessage(newRobot *structs.Robot) {
|
|
totalPages := cache.GetAllRobots(rspagination.PageQuery{Page: 1}).TotalPages
|
|
|
|
apiRobot := structs.APIRobot{
|
|
Id: newRobot.Id,
|
|
Type: newRobot.Type,
|
|
Name: newRobot.Name,
|
|
Status: newRobot.Status,
|
|
Address: newRobot.Address,
|
|
CurrentJobName: newRobot.CurrentJobName,
|
|
JobsWaitingCount: newRobot.JobsWaitingCount,
|
|
JobsWaitingNameList: []string{},
|
|
FirmwareVersion: newRobot.FirmwareVersion,
|
|
ConnectedAt: newRobot.ConnectedAt,
|
|
CreatedAt: newRobot.CreatedAt,
|
|
}
|
|
|
|
robot.BroadcastSSEMessage(structs.SSEMessage{
|
|
Cmd: utils.SSESentCmdAddRobot,
|
|
Body: struct {
|
|
Robot *structs.APIRobot
|
|
TotalPages int
|
|
UnauthorizedRobotsTotalPages int
|
|
}{
|
|
Robot: &apiRobot,
|
|
TotalPages: totalPages,
|
|
UnauthorizedRobotsTotalPages: cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages,
|
|
},
|
|
})
|
|
}
|
|
|
|
func AuthorizeRobot(c *fiber.Ctx) error {
|
|
// swagger:operation POST /robot/authorize/{robotId} robot robotAuthorize
|
|
// ---
|
|
// summary: Authorize robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: params
|
|
// name: robotId
|
|
// description: Robot id.
|
|
// required: true
|
|
// schema:
|
|
// type: string
|
|
// responses:
|
|
// "200":
|
|
// description: Robot authorized
|
|
// "400":
|
|
// description: Invalid robot id
|
|
// "422":
|
|
// description: Robot not found
|
|
|
|
var params structs.RobotIdParams
|
|
|
|
if err := rsutils.ParamsParserHelper(c, ¶ms); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
if !cache.IsUnauthorizedRobotInList(params.RobotId) {
|
|
logger.AddSystemLog(rslogger.LogTypeWarning, "Unauthorized robot with id %v not found", params.RobotId)
|
|
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
unauthorizedRobot := cache.GetUnauthorizedRobotById(params.RobotId)
|
|
|
|
if unauthorizedRobot.Id == "" {
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
newRobot := structs.Robot{
|
|
Id: params.RobotId,
|
|
Type: unauthorizedRobot.Type,
|
|
Name: uuid.New().String(),
|
|
Address: unauthorizedRobot.Address,
|
|
Status: utils.RobotStatusIdle,
|
|
FirmwareVersion: unauthorizedRobot.FirmwareVersion,
|
|
ConnectedAt: unauthorizedRobot.ConnectedAt,
|
|
CreatedAt: unauthorizedRobot.CreatedAt,
|
|
}
|
|
|
|
cache.AddRobot(&newRobot)
|
|
database.DB.Create(&newRobot)
|
|
|
|
cache.RemoveUnauthorizedRobotById(params.RobotId)
|
|
|
|
addRobotSSEMessage(&newRobot)
|
|
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Robot authorized with id %v and type %v", params.RobotId, utils.GetRobotTypeString(unauthorizedRobot.Type))
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func DeleteRobot(c *fiber.Ctx) error {
|
|
// swagger:operation DELETE /robot/{robotId} robot robotDelete
|
|
// ---
|
|
// summary: Delete robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: params
|
|
// name: robotId
|
|
// description: Robot id.
|
|
// required: true
|
|
// schema:
|
|
// type: string
|
|
// responses:
|
|
// "200":
|
|
// description: Robot deleted
|
|
// "400":
|
|
// description: Invalid robot id
|
|
|
|
var params structs.RobotIdParams
|
|
|
|
if err := rsutils.ParamsParserHelper(c, ¶ms); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
database.DB.Delete(&structs.Robot{}, "id = ?", params.RobotId)
|
|
cache.RemoveRobotById(params.RobotId)
|
|
|
|
robot.BroadcastSSEMessage(structs.SSEMessage{
|
|
Cmd: utils.SSESentCmdRemoveRobot,
|
|
Body: struct {
|
|
RobotId string
|
|
TotalPages int
|
|
}{
|
|
RobotId: params.RobotId,
|
|
TotalPages: cache.GetAllRobots(rspagination.PageQuery{Page: 1}).TotalPages,
|
|
},
|
|
})
|
|
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Robot deleted with id %v", params.RobotId)
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func DenyUnauthorizedRobot(c *fiber.Ctx) error {
|
|
// swagger:operation DELETE /robot/deny/{robotId} robot robotDenyUnauthorizedRobot
|
|
// ---
|
|
// summary: Deny unauthorized robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: params
|
|
// name: robotId
|
|
// description: Robot id.
|
|
// required: true
|
|
// schema:
|
|
// type: string
|
|
// responses:
|
|
// "200":
|
|
// description: Robot denied
|
|
// "400":
|
|
// description: Invalid robot id
|
|
|
|
var params structs.RobotIdParams
|
|
|
|
if err := rsutils.ParamsParserHelper(c, ¶ms); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
cache.RemoveUnauthorizedRobotById(params.RobotId)
|
|
|
|
robot.BroadcastSSEMessage(structs.SSEMessage{
|
|
Cmd: utils.SSESentCmdRemoveUnauthorizedRobot,
|
|
Body: struct {
|
|
UnauthorizedRobotId string
|
|
TotalPages int
|
|
}{
|
|
UnauthorizedRobotId: params.RobotId,
|
|
TotalPages: cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages,
|
|
},
|
|
})
|
|
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Unauthorized robot denied with id %v", params.RobotId)
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func UpdateRobot(c *fiber.Ctx) error {
|
|
// swagger:operation PATCH /robot robot robotUpdate
|
|
// ---
|
|
// summary: Update robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: body
|
|
// name: body
|
|
// description: Update robot body.
|
|
// required: true
|
|
// schema:
|
|
// "$ref": "#/definitions/Robot"
|
|
// responses:
|
|
// "200":
|
|
// description: Robot updated
|
|
// "400":
|
|
// description: Invalid request body
|
|
// "422":
|
|
// description: Robot not found
|
|
|
|
var body structs.UpdateRobotBody
|
|
|
|
if err := rsutils.BodyParserHelper(c, &body); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
foundRobot := cache.GetRobotById(body.RobotId)
|
|
|
|
if foundRobot == nil || cache.IsRobotNameInList(body.RobotName) {
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Robot with id %v not found", body.RobotId)
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
foundRobot.Name = body.RobotName
|
|
|
|
database.DB.Model(&structs.Robot{}).
|
|
Where("id = ?", foundRobot.Id).
|
|
Update("name", foundRobot.Name)
|
|
|
|
robot.BroadcastSSEMessage(structs.SSEMessage{
|
|
Cmd: utils.SSESentCmdRobotUpdated,
|
|
Body: body,
|
|
})
|
|
|
|
logger.AddSystemLog(rslogger.LogTypeInfo, "Robot with id %v name changed to %v", body.RobotId, body.RobotName)
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
// This will be used to free up a job from a robot if it is stuck or job was not correctly finished
|
|
func FreeUpJob(c *fiber.Ctx) error {
|
|
// swagger:operation PATCH /robot/fuj/{robotId} robot robotFreeUpJob
|
|
// ---
|
|
// summary: Free up job from robot.
|
|
// consumes:
|
|
// - application/json
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - in: params
|
|
// name: robotId
|
|
// description: Robot id.
|
|
// required: true
|
|
// schema:
|
|
// type: string
|
|
// responses:
|
|
// "200":
|
|
// description: Job freed up
|
|
// "400":
|
|
// description: Invalid request body
|
|
// "422":
|
|
// description: Invalid robot id or robot is not running or waiting
|
|
|
|
var params structs.RobotIdParams
|
|
|
|
if err := rsutils.ParamsParserHelper(c, ¶ms); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
foundRobot := cache.GetRobotById(params.RobotId)
|
|
|
|
if foundRobot == nil {
|
|
logger.AddSystemLog(rslogger.LogTypeWarning, "Robot %v not found. Cannot free ub job.", params.RobotId)
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
if foundRobot.Status != utils.RobotStatusRunning && foundRobot.Status != utils.RobotStatusWaiting {
|
|
logger.AddSystemLog(rslogger.LogTypeWarning, "Robot %v is not running or waiting. Cannot free up job.", params.RobotId)
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
robot.FreeUpJob(foundRobot, utils.RobotStatusIdle)
|
|
|
|
logger.AddRobotLog(rslogger.LogTypeWarning, foundRobot.Type, foundRobot.Id, "Job freed up")
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|