added total pages for pagination handling on web

main
alex 2023-10-16 19:55:50 +02:00
parent e2c68c8c69
commit 75d7f44a55
11 changed files with 238 additions and 99 deletions

View File

@ -16,7 +16,6 @@ package main
import ( import (
"fmt" "fmt"
"jannex/robot-control-manager/modules/cache"
"jannex/robot-control-manager/modules/config" "jannex/robot-control-manager/modules/config"
"jannex/robot-control-manager/modules/database" "jannex/robot-control-manager/modules/database"
"jannex/robot-control-manager/modules/robot" "jannex/robot-control-manager/modules/robot"
@ -72,9 +71,6 @@ func main() {
router.SetupRoutes(app) router.SetupRoutes(app)
// TODO: Remove this
cache.SetPermitJoin(true)
rcmlogger.AddSystemLog("Server started") rcmlogger.AddSystemLog("Server started")
robot.LoadRobotsFromDatabase() robot.LoadRobotsFromDatabase()

View File

@ -18,3 +18,10 @@ func IsPermitJoinEnabled() bool {
return permitJoin return permitJoin
} }
func GetPermitJoin() bool {
pjMu.RLock()
defer pjMu.RUnlock()
return permitJoin
}

View File

@ -3,6 +3,7 @@ package cache
import ( import (
"jannex/robot-control-manager/modules/structs" "jannex/robot-control-manager/modules/structs"
"jannex/robot-control-manager/modules/utils" "jannex/robot-control-manager/modules/utils"
"sort"
"sync" "sync"
"git.ex.umbach.dev/Alex/roese-utils/rspagination" "git.ex.umbach.dev/Alex/roese-utils/rspagination"
@ -57,6 +58,11 @@ func GetAllRobots(query rspagination.PageQuery) structs.RobotsResponse {
}) })
} }
// sort after created at
sort.SliceStable(r, func(i, j int) bool {
return r[i].CreatedAt.After(r[j].CreatedAt)
})
start, end := rspagination.GetPage(len(r), query.Page, utils.RobotsPageLimit) start, end := rspagination.GetPage(len(r), query.Page, utils.RobotsPageLimit)
return structs.RobotsResponse{ return structs.RobotsResponse{

View File

@ -216,23 +216,23 @@ func BroadcastSSEMessage(message structs.SSEMessage) {
} }
} }
/* var PermitJoinTimer *time.Timer
func AddJobNameToJobsWaitingList(r *structs.Robot, jobName string) {
r.JobMutex.Lock()
defer r.JobMutex.Unlock()
r.JobsWaitingNameList = append(r.JobsWaitingNameList, jobName) func PermitJoinAutoDisableHandler() {
} if PermitJoinTimer != nil {
PermitJoinTimer.Stop()
func RemoveJobNameFromJobsWaitingList(r *structs.Robot, jobName string) {
r.JobMutex.Lock()
defer r.JobMutex.Unlock()
for i, j := range r.JobsWaitingNameList {
if j == jobName {
r.JobsWaitingNameList = append(r.JobsWaitingNameList[:i], r.JobsWaitingNameList[i+1:]...)
break
}
} }
PermitJoinTimer = time.NewTimer(utils.RobotsPermitJoinAutoDisable * time.Second)
<-PermitJoinTimer.C
cache.SetPermitJoin(false)
BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdPermitJoinUpdated,
Body: 0,
})
logger.AddSystemLog("Permit join disabled by timer")
} }
*/

View File

@ -3,3 +3,8 @@ package structs
type PermitJoinParam struct { type PermitJoinParam struct {
Enabled uint8 Enabled uint8
} }
// swagger:model PermitJoinResponse
type PermitJoinResponse struct {
Enabled bool
}

View File

@ -4,6 +4,7 @@ const (
RobotPingRetries = 3 RobotPingRetries = 3
RobotPingHandlerInterval = 5 // seconds RobotPingHandlerInterval = 5 // seconds
RobotsPageLimit = 10 RobotsPageLimit = 10
RobotsPermitJoinAutoDisable = 120 // seconds
UnauthorizedRobotsPageLimit = 10 UnauthorizedRobotsPageLimit = 10
minRobotNameLength = "2" minRobotNameLength = "2"
@ -32,6 +33,7 @@ const (
SSESentCmdRobotUpdated = 6 SSESentCmdRobotUpdated = 6
SSESentCmdUpdateRobotCurrentJob = 7 SSESentCmdUpdateRobotCurrentJob = 7
SSESentCmdUpdateRobotJobsWaitingCount = 8 SSESentCmdUpdateRobotJobsWaitingCount = 8
SSESentCmdPermitJoinUpdated = 9
) )
var ( var (

View File

@ -141,6 +141,27 @@
} }
} }
}, },
"/permitjoin": {
"get": {
"description": "This is used to get the current permit join status.\n",
"produces": [
"application/json"
],
"tags": [
"permitjoin"
],
"summary": "Get permit join.",
"operationId": "getPermitJoin",
"responses": {
"200": {
"description": "Permit join status",
"schema": {
"$ref": "#/definitions/PermitJoinResponse"
}
}
}
}
},
"/permitjoin/{enabled}": { "/permitjoin/{enabled}": {
"post": { "post": {
"description": "This is used to enable or disable permit join.\n", "description": "This is used to enable or disable permit join.\n",
@ -213,6 +234,41 @@
"description": "Permit join is enabled" "description": "Permit join is enabled"
} }
} }
},
"patch": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"robot"
],
"summary": "Update robot.",
"operationId": "robotUpdate",
"parameters": [
{
"description": "Update robot body.",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/Robot"
}
}
],
"responses": {
"200": {
"description": "Robot updated"
},
"400": {
"description": "Invalid request body"
},
"422": {
"description": "Robot not found"
}
}
} }
}, },
"/robot/authorize/{robotId}": { "/robot/authorize/{robotId}": {
@ -322,6 +378,53 @@
} }
}, },
"definitions": { "definitions": {
"APIRobot": {
"type": "object",
"properties": {
"Address": {
"type": "string"
},
"ConnectedAt": {
"type": "string",
"format": "date-time"
},
"CreatedAt": {
"type": "string",
"format": "date-time"
},
"CurrentJobName": {
"type": "string"
},
"FirmwareVersion": {
"type": "string"
},
"Id": {
"type": "string"
},
"JobsWaitingCount": {
"type": "integer",
"format": "int64"
},
"JobsWaitingNameList": {
"type": "array",
"items": {
"type": "string"
}
},
"Name": {
"type": "string"
},
"Status": {
"type": "integer",
"format": "uint8"
},
"Type": {
"type": "integer",
"format": "uint8"
}
},
"x-go-package": "jannex/robot-control-manager/modules/structs"
},
"ControlBody": { "ControlBody": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -381,66 +484,11 @@
}, },
"x-go-package": "jannex/robot-control-manager/modules/structs" "x-go-package": "jannex/robot-control-manager/modules/structs"
}, },
"Mutex": { "PermitJoinResponse": {
"description": "A Mutex must not be copied after first use.\n\nIn the terminology of the Go memory model,\nthe n'th call to Unlock “synchronizes before” the m'th call to Lock\nfor any n \u003c m.\nA successful call to TryLock is equivalent to a call to Lock.\nA failed call to TryLock does not establish any “synchronizes before”\nrelation at all.",
"type": "object",
"title": "A Mutex is a mutual exclusion lock.\nThe zero value for a Mutex is an unlocked mutex.",
"x-go-package": "sync"
},
"Robot": {
"type": "object", "type": "object",
"properties": { "properties": {
"Address": { "Enabled": {
"type": "string" "type": "boolean"
},
"ConnectedAt": {
"type": "string",
"format": "date-time"
},
"CreatedAt": {
"type": "string",
"format": "date-time"
},
"CurrentJobId": {
"type": "string"
},
"CurrentJobName": {
"type": "string"
},
"Id": {
"type": "string"
},
"JobMutex": {
"$ref": "#/definitions/Mutex"
},
"JobsWaitingCount": {
"type": "integer",
"format": "int64"
},
"JobsWaitingNameList": {
"type": "array",
"items": {
"type": "string"
}
},
"LastTaskAt": {
"type": "string",
"format": "date-time"
},
"Name": {
"type": "string"
},
"PingRetries": {
"type": "integer",
"format": "uint8"
},
"Status": {
"type": "integer",
"format": "uint8"
},
"Type": {
"type": "integer",
"format": "uint8"
} }
}, },
"x-go-package": "jannex/robot-control-manager/modules/structs" "x-go-package": "jannex/robot-control-manager/modules/structs"
@ -451,7 +499,7 @@
"Robots": { "Robots": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Robot" "$ref": "#/definitions/APIRobot"
} }
}, },
"TotalPages": { "TotalPages": {
@ -484,6 +532,9 @@
"type": "string", "type": "string",
"format": "date-time" "format": "date-time"
}, },
"FirmwareVersion": {
"type": "string"
},
"Id": { "Id": {
"type": "string" "type": "string"
}, },

View File

@ -3,7 +3,9 @@ package permitjoin
import ( import (
"jannex/robot-control-manager/modules/cache" "jannex/robot-control-manager/modules/cache"
"jannex/robot-control-manager/modules/logger" "jannex/robot-control-manager/modules/logger"
"jannex/robot-control-manager/modules/robot"
"jannex/robot-control-manager/modules/structs" "jannex/robot-control-manager/modules/structs"
"jannex/robot-control-manager/modules/utils"
"git.ex.umbach.dev/Alex/roese-utils/rsutils" "git.ex.umbach.dev/Alex/roese-utils/rsutils"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
@ -38,12 +40,38 @@ func SetPermitJoin(c *fiber.Ctx) error {
if params.Enabled == 0 { if params.Enabled == 0 {
cache.SetPermitJoin(false) cache.SetPermitJoin(false)
logger.AddSystemLog("Permit join disabled") logger.AddSystemLog("Permit join disabled")
robot.PermitJoinTimer.Stop()
} else { } else {
cache.SetPermitJoin(true) cache.SetPermitJoin(true)
logger.AddSystemLog("Permit join enabled") logger.AddSystemLog("Permit join enabled")
go robot.PermitJoinAutoDisableHandler()
} }
// TODO: sse robot.BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdPermitJoinUpdated,
Body: params.Enabled == 1,
})
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
func GetPermitJoin(c *fiber.Ctx) error {
// swagger:operation GET /permitjoin permitjoin getPermitJoin
// ---
// summary: Get permit join.
// description: |
// This is used to get the current permit join status.
// produces:
// - application/json
// responses:
// "200":
// description: Permit join status
// schema:
// "$ref": "#/definitions/PermitJoinResponse"
return c.JSON(structs.PermitJoinResponse{
Enabled: cache.GetPermitJoin(),
})
}

View File

@ -9,6 +9,7 @@ import (
"jannex/robot-control-manager/modules/utils" "jannex/robot-control-manager/modules/utils"
"time" "time"
"git.ex.umbach.dev/Alex/roese-utils/rspagination"
"git.ex.umbach.dev/Alex/roese-utils/rsutils" "git.ex.umbach.dev/Alex/roese-utils/rsutils"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/google/uuid" "github.com/google/uuid"
@ -71,9 +72,17 @@ func FirstRequest(c *fiber.Ctx) error {
cache.AddUnauthorizedRobot(&newUnauthorizedRobot) cache.AddUnauthorizedRobot(&newUnauthorizedRobot)
totalPages := cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages
robot.BroadcastSSEMessage(structs.SSEMessage{ robot.BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdAddUnauthorizedRobot, Cmd: utils.SSESentCmdAddUnauthorizedRobot,
Body: &newUnauthorizedRobot, Body: struct {
UnauthorizedRobot *structs.UnauthorizedRobot
TotalPages int
}{
UnauthorizedRobot: &newUnauthorizedRobot,
TotalPages: totalPages,
},
}) })
logger.AddSystemLog("Unauthorized robot connected with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type)) logger.AddSystemLog("Unauthorized robot connected with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type))
@ -101,10 +110,7 @@ func FirstRequest(c *fiber.Ctx) error {
FirmwareVersion: newRobot.FirmwareVersion, FirmwareVersion: newRobot.FirmwareVersion,
}) })
robot.BroadcastSSEMessage(structs.SSEMessage{ addRobotSSEMessage(&newRobot)
Cmd: utils.SSESentCmdAddRobot,
Body: &newRobot,
})
logger.AddSystemLog("Robot connected with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type)) logger.AddSystemLog("Robot connected with id %v and type %v", body.Id, utils.GetRobotTypeString(body.Type))
} }
@ -112,6 +118,23 @@ func FirstRequest(c *fiber.Ctx) error {
return c.JSON(structs.StatusResponse{Status: "ok"}) return c.JSON(structs.StatusResponse{Status: "ok"})
} }
func addRobotSSEMessage(newRobot *structs.Robot) {
totalPages := cache.GetAllRobots(rspagination.PageQuery{Page: 1}).TotalPages
robot.BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdAddRobot,
Body: struct {
Robot *structs.Robot
TotalPages int
UnauthorizedRobotsTotalPages int
}{
Robot: newRobot,
TotalPages: totalPages,
UnauthorizedRobotsTotalPages: cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages,
},
})
}
func AuthorizeRobot(c *fiber.Ctx) error { func AuthorizeRobot(c *fiber.Ctx) error {
// swagger:operation POST /robot/authorize/{robotId} robot robotAuthorize // swagger:operation POST /robot/authorize/{robotId} robot robotAuthorize
// --- // ---
@ -169,10 +192,7 @@ func AuthorizeRobot(c *fiber.Ctx) error {
cache.RemoveUnauthorizedRobotById(params.RobotId) cache.RemoveUnauthorizedRobotById(params.RobotId)
robot.BroadcastSSEMessage(structs.SSEMessage{ addRobotSSEMessage(&newRobot)
Cmd: utils.SSESentCmdAddRobot,
Body: &newRobot,
})
logger.AddSystemLog("Robot authorized with id %v and type %v", params.RobotId, utils.GetRobotTypeString(unauthorizedRobot.Type)) logger.AddSystemLog("Robot authorized with id %v and type %v", params.RobotId, utils.GetRobotTypeString(unauthorizedRobot.Type))
@ -210,8 +230,14 @@ func DeleteRobot(c *fiber.Ctx) error {
cache.RemoveRobotById(params.RobotId) cache.RemoveRobotById(params.RobotId)
robot.BroadcastSSEMessage(structs.SSEMessage{ robot.BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdRemoveRobot, Cmd: utils.SSESentCmdRemoveRobot,
Body: params.RobotId, Body: struct {
RobotId string
TotalPages int
}{
RobotId: params.RobotId,
TotalPages: cache.GetAllRobots(rspagination.PageQuery{Page: 1}).TotalPages,
},
}) })
logger.AddSystemLog("Robot deleted with id %v", params.RobotId) logger.AddSystemLog("Robot deleted with id %v", params.RobotId)
@ -249,8 +275,14 @@ func DenyUnauthorizedRobot(c *fiber.Ctx) error {
cache.RemoveUnauthorizedRobotById(params.RobotId) cache.RemoveUnauthorizedRobotById(params.RobotId)
robot.BroadcastSSEMessage(structs.SSEMessage{ robot.BroadcastSSEMessage(structs.SSEMessage{
Cmd: utils.SSESentCmdRemoveUnauthorizedRobot, Cmd: utils.SSESentCmdRemoveUnauthorizedRobot,
Body: params.RobotId, Body: struct {
UnauthorizedRobotId string
TotalPages int
}{
UnauthorizedRobotId: params.RobotId,
TotalPages: cache.GetAllUnauthorizedRobots(rspagination.PageQuery{Page: 1}).TotalPages,
},
}) })
logger.AddSystemLog("Unauthorized robot denied with id %v", params.RobotId) logger.AddSystemLog("Unauthorized robot denied with id %v", params.RobotId)

View File

@ -32,6 +32,7 @@ func SetupRoutes(app *fiber.App) {
pj := v1.Group("/permitjoin") pj := v1.Group("/permitjoin")
pj.Post("/:enabled", permitjoin.SetPermitJoin) pj.Post("/:enabled", permitjoin.SetPermitJoin)
pj.Get("/", permitjoin.GetPermitJoin)
v1.Get("/sse", sse.SSE) v1.Get("/sse", sse.SSE)

View File

@ -3,12 +3,13 @@
from flask import Flask, request, jsonify from flask import Flask, request, jsonify
import requests import requests
import time import time
import random
robot_control_server_url = 'http://localhost:50055/v1' robot_control_server_url = 'http://localhost:50055/v1'
class RexRobot: class RexRobot:
def __init__(self): def __init__(self, id):
self.id = "B29" self.id = id
self.firmwareVersion = "0.0.1" self.firmwareVersion = "0.0.1"
self.currentJobId = "" self.currentJobId = ""
@ -25,7 +26,17 @@ class RexRobot:
def setCurrentJobId(self, jobId): def setCurrentJobId(self, jobId):
self.currentJobId = jobId self.currentJobId = jobId
rex = RexRobot() # generate random id
def randomId():
return random.randint(0, 100000)
# 10 random rexrobot
for i in range(10):
RexRobot(str(randomId()))
rex = RexRobot("test")
app = Flask(__name__) app = Flask(__name__)
@ -48,4 +59,4 @@ def ping():
return jsonify({'status': 'ok'}) return jsonify({'status': 'ok'})
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=False, port=5000) app.run(debug=False, port=5003)