document more swagger endpoints + cleanup source

This commit is contained in:
Cedric Verstraeten
2023-12-11 21:02:01 +01:00
parent 898b3a52c2
commit 9151b38e7f
7 changed files with 493 additions and 173 deletions

View File

@@ -293,6 +293,75 @@ const docTemplate = `{
}
}
},
"/api/config": {
"get": {
"description": "Get the current configuration.",
"tags": [
"general"
],
"summary": "Get the current configuration.",
"operationId": "config",
"responses": {
"200": {
"description": ""
}
}
},
"post": {
"description": "Update the current configuration.",
"tags": [
"general"
],
"summary": "Update the current configuration.",
"operationId": "config",
"parameters": [
{
"description": "Configuration",
"name": "config",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Config"
}
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/dashboard": {
"get": {
"description": "Get all information showed on the dashboard.",
"tags": [
"general"
],
"summary": "Get all information showed on the dashboard.",
"operationId": "dashboard",
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/days": {
"get": {
"description": "Get all days stored in the recordings directory.",
"tags": [
"general"
],
"summary": "Get all days stored in the recordings directory.",
"operationId": "days",
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/hub/verify": {
"post": {
"security": [
@@ -302,7 +371,7 @@ const docTemplate = `{
],
"description": "Will verify the hub connectivity.",
"tags": [
"config"
"general"
],
"summary": "Will verify the hub connectivity.",
"operationId": "verify-hub",
@@ -327,6 +396,32 @@ const docTemplate = `{
}
}
},
"/api/latest-events": {
"post": {
"description": "Get the latest recordings (events) from the recordings directory.",
"tags": [
"general"
],
"summary": "Get the latest recordings (events) from the recordings directory.",
"operationId": "latest-events",
"parameters": [
{
"description": "Event filter",
"name": "eventFilter",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.EventFilter"
}
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/login": {
"post": {
"description": "Get Authorization token.",
@@ -365,7 +460,7 @@ const docTemplate = `{
],
"description": "Will verify the ONVIF connectivity.",
"tags": [
"config"
"general"
],
"summary": "Will verify the ONVIF connectivity.",
"operationId": "verify-onvif",
@@ -399,7 +494,7 @@ const docTemplate = `{
],
"description": "Will verify the persistence.",
"tags": [
"config"
"general"
],
"summary": "Will verify the persistence.",
"operationId": "verify-persistence",
@@ -685,6 +780,20 @@ const docTemplate = `{
}
}
},
"models.EventFilter": {
"type": "object",
"properties": {
"number_of_elements": {
"type": "integer"
},
"timestamp_offset_end": {
"type": "integer"
},
"timestamp_offset_start": {
"type": "integer"
}
}
},
"models.IPCamera": {
"type": "object",
"properties": {

View File

@@ -285,6 +285,75 @@
}
}
},
"/api/config": {
"get": {
"description": "Get the current configuration.",
"tags": [
"general"
],
"summary": "Get the current configuration.",
"operationId": "config",
"responses": {
"200": {
"description": ""
}
}
},
"post": {
"description": "Update the current configuration.",
"tags": [
"general"
],
"summary": "Update the current configuration.",
"operationId": "config",
"parameters": [
{
"description": "Configuration",
"name": "config",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Config"
}
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/dashboard": {
"get": {
"description": "Get all information showed on the dashboard.",
"tags": [
"general"
],
"summary": "Get all information showed on the dashboard.",
"operationId": "dashboard",
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/days": {
"get": {
"description": "Get all days stored in the recordings directory.",
"tags": [
"general"
],
"summary": "Get all days stored in the recordings directory.",
"operationId": "days",
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/hub/verify": {
"post": {
"security": [
@@ -294,7 +363,7 @@
],
"description": "Will verify the hub connectivity.",
"tags": [
"config"
"general"
],
"summary": "Will verify the hub connectivity.",
"operationId": "verify-hub",
@@ -319,6 +388,32 @@
}
}
},
"/api/latest-events": {
"post": {
"description": "Get the latest recordings (events) from the recordings directory.",
"tags": [
"general"
],
"summary": "Get the latest recordings (events) from the recordings directory.",
"operationId": "latest-events",
"parameters": [
{
"description": "Event filter",
"name": "eventFilter",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.EventFilter"
}
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/api/login": {
"post": {
"description": "Get Authorization token.",
@@ -357,7 +452,7 @@
],
"description": "Will verify the ONVIF connectivity.",
"tags": [
"config"
"general"
],
"summary": "Will verify the ONVIF connectivity.",
"operationId": "verify-onvif",
@@ -391,7 +486,7 @@
],
"description": "Will verify the persistence.",
"tags": [
"config"
"general"
],
"summary": "Will verify the persistence.",
"operationId": "verify-persistence",
@@ -677,6 +772,20 @@
}
}
},
"models.EventFilter": {
"type": "object",
"properties": {
"number_of_elements": {
"type": "integer"
},
"timestamp_offset_end": {
"type": "integer"
},
"timestamp_offset_start": {
"type": "integer"
}
}
},
"models.IPCamera": {
"type": "object",
"properties": {

View File

@@ -171,6 +171,15 @@ definitions:
symmetric_key:
type: string
type: object
models.EventFilter:
properties:
number_of_elements:
type: integer
timestamp_offset_end:
type: integer
timestamp_offset_start:
type: integer
type: object
models.IPCamera:
properties:
fps:
@@ -500,6 +509,52 @@ paths:
summary: Validate a specific RTSP profile camera connection.
tags:
- camera
/api/config:
get:
description: Get the current configuration.
operationId: config
responses:
"200":
description: ""
summary: Get the current configuration.
tags:
- general
post:
description: Update the current configuration.
operationId: config
parameters:
- description: Configuration
in: body
name: config
required: true
schema:
$ref: '#/definitions/models.Config'
responses:
"200":
description: ""
summary: Update the current configuration.
tags:
- general
/api/dashboard:
get:
description: Get all information showed on the dashboard.
operationId: dashboard
responses:
"200":
description: ""
summary: Get all information showed on the dashboard.
tags:
- general
/api/days:
get:
description: Get all days stored in the recordings directory.
operationId: days
responses:
"200":
description: ""
summary: Get all days stored in the recordings directory.
tags:
- general
/api/hub/verify:
post:
description: Will verify the hub connectivity.
@@ -520,7 +575,24 @@ paths:
- Bearer: []
summary: Will verify the hub connectivity.
tags:
- config
- general
/api/latest-events:
post:
description: Get the latest recordings (events) from the recordings directory.
operationId: latest-events
parameters:
- description: Event filter
in: body
name: eventFilter
required: true
schema:
$ref: '#/definitions/models.EventFilter'
responses:
"200":
description: ""
summary: Get the latest recordings (events) from the recordings directory.
tags:
- general
/api/login:
post:
description: Get Authorization token.
@@ -560,7 +632,7 @@ paths:
- Bearer: []
summary: Will verify the ONVIF connectivity.
tags:
- config
- general
/api/persistence/verify:
post:
description: Will verify the persistence.
@@ -581,7 +653,7 @@ paths:
- Bearer: []
summary: Will verify the persistence.
tags:
- config
- general
securityDefinitions:
Bearer:
in: header

View File

@@ -602,7 +602,7 @@ func HandleLiveStreamHD(livestreamCursor *packets.QueueCursor, configuration *mo
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @Tags config
// @Tags general
// @Param config body models.Config true "Config"
// @Summary Will verify the hub connectivity.
// @Description Will verify the hub connectivity.
@@ -672,7 +672,7 @@ func VerifyHub(c *gin.Context) {
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @Tags config
// @Tags general
// @Param config body models.Config true "Config"
// @Summary Will verify the persistence.
// @Description Will verify the persistence.

View File

@@ -19,6 +19,7 @@ import (
"github.com/kerberos-io/agent/machinery/src/onvif"
"github.com/kerberos-io/agent/machinery/src/packets"
routers "github.com/kerberos-io/agent/machinery/src/routers/mqtt"
"github.com/kerberos-io/agent/machinery/src/utils"
"github.com/tevino/abool"
)
@@ -434,6 +435,119 @@ func ControlAgent(communication *models.Communication) {
log.Log.Debug("components.Kerberos.ControlAgent(): finished")
}
// GetDashboard godoc
// @Router /api/dashboard [get]
// @ID dashboard
// @Tags general
// @Summary Get all information showed on the dashboard.
// @Description Get all information showed on the dashboard.
// @Success 200
func GetDashboard(c *gin.Context, configDirectory string, configuration *models.Configuration, communication *models.Communication) {
// Check if camera is online.
cameraIsOnline := communication.CameraConnected
// If an agent is properly setup with Kerberos Hub, we will send
// a ping to Kerberos Hub every 15seconds. On receiving a positive response
// it will update the CloudTimestamp value.
cloudIsOnline := false
if communication.CloudTimestamp != nil && communication.CloudTimestamp.Load() != nil {
timestamp := communication.CloudTimestamp.Load().(int64)
if timestamp > 0 {
cloudIsOnline = true
}
}
// The total number of recordings stored in the directory.
recordingDirectory := configDirectory + "/data/recordings"
numberOfRecordings := utils.NumberOfMP4sInDirectory(recordingDirectory)
// All days stored in this agent.
days := []string{}
latestEvents := []models.Media{}
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
// Get All days
days = utils.GetDays(events, recordingDirectory, configuration)
// Get all latest events
var eventFilter models.EventFilter
eventFilter.NumberOfElements = 5
latestEvents = utils.GetMediaFormatted(events, recordingDirectory, configuration, eventFilter) // will get 5 latest recordings.
}
c.JSON(200, gin.H{
"offlineMode": configuration.Config.Offline,
"cameraOnline": cameraIsOnline,
"cloudOnline": cloudIsOnline,
"numberOfRecordings": numberOfRecordings,
"days": days,
"latestEvents": latestEvents,
})
}
// GetLatestEvents godoc
// @Router /api/latest-events [post]
// @ID latest-events
// @Tags general
// @Param eventFilter body models.EventFilter true "Event filter"
// @Summary Get the latest recordings (events) from the recordings directory.
// @Description Get the latest recordings (events) from the recordings directory.
// @Success 200
func GetLatestEvents(c *gin.Context, configDirectory string, configuration *models.Configuration, communication *models.Communication) {
var eventFilter models.EventFilter
err := c.BindJSON(&eventFilter)
if err == nil {
// Default to 10 if no limit is set.
if eventFilter.NumberOfElements == 0 {
eventFilter.NumberOfElements = 10
}
recordingDirectory := configDirectory + "/data/recordings"
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
// We will get all recordings from the directory (as defined by the filter).
fileObjects := utils.GetMediaFormatted(events, recordingDirectory, configuration, eventFilter)
c.JSON(200, gin.H{
"events": fileObjects,
})
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
}
// GetDays godoc
// @Router /api/days [get]
// @ID days
// @Tags general
// @Summary Get all days stored in the recordings directory.
// @Description Get all days stored in the recordings directory.
// @Success 200
func GetDays(c *gin.Context, configDirectory string, configuration *models.Configuration, communication *models.Communication) {
recordingDirectory := configDirectory + "/data/recordings"
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
days := utils.GetDays(events, recordingDirectory, configuration)
c.JSON(200, gin.H{
"events": days,
})
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
}
// StopAgent godoc
// @Router /api/camera/stop [post]
// @ID camera-stop
@@ -482,3 +596,54 @@ func MakeRecording(c *gin.Context, communication *models.Communication) {
"recording": true,
})
}
// GetConfig godoc
// @Router /api/config [get]
// @ID config
// @Tags general
// @Summary Get the current configuration.
// @Description Get the current configuration.
// @Success 200
func GetConfig(c *gin.Context, captureDevice *capture.Capture, configuration *models.Configuration, communication *models.Communication) {
// We'll try to get a snapshot from the camera.
base64Image := capture.Base64Image(captureDevice, communication)
if base64Image != "" {
communication.Image = base64Image
}
c.JSON(200, gin.H{
"config": configuration.Config,
"custom": configuration.CustomConfig,
"global": configuration.GlobalConfig,
"snapshot": communication.Image,
})
}
// UpdateConfig godoc
// @Router /api/config [post]
// @ID config
// @Tags general
// @Param config body models.Config true "Configuration"
// @Summary Update the current configuration.
// @Description Update the current configuration.
// @Success 200
func UpdateConfig(c *gin.Context, configDirectory string, configuration *models.Configuration, communication *models.Communication) {
var config models.Config
err := c.BindJSON(&config)
if err == nil {
err := configService.SaveConfig(configDirectory, config, configuration, communication)
if err == nil {
c.JSON(200, gin.H{
"data": "☄ Reconfiguring",
})
} else {
c.JSON(200, gin.H{
"data": "☄ Reconfiguring",
})
}
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
}

View File

@@ -851,7 +851,7 @@ func GetPTZFunctionsFromDevice(configurations ptz.GetConfigurationsResponse) ([]
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @Tags config
// @Tags general
// @Param cameraConfig body models.IPCamera true "Camera Config"
// @Summary Will verify the ONVIF connectivity.
// @Description Will verify the ONVIF connectivity.

View File

@@ -9,9 +9,7 @@ import (
"github.com/kerberos-io/agent/machinery/src/routers/websocket"
"github.com/kerberos-io/agent/machinery/src/cloud"
configService "github.com/kerberos-io/agent/machinery/src/config"
"github.com/kerberos-io/agent/machinery/src/models"
"github.com/kerberos-io/agent/machinery/src/utils"
)
func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirectory string, configuration *models.Configuration, communication *models.Communication, captureDevice *capture.Capture) *gin.RouterGroup {
@@ -23,42 +21,13 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirect
// This is legacy should be removed in future! Now everything
// lives under the /api prefix.
r.GET("/config", func(c *gin.Context) {
// We'll try to get a snapshot from the camera.
base64Image := capture.Base64Image(captureDevice, communication)
if base64Image != "" {
communication.Image = base64Image
}
c.JSON(200, gin.H{
"config": configuration.Config,
"custom": configuration.CustomConfig,
"global": configuration.GlobalConfig,
"snapshot": communication.Image,
})
components.GetConfig(c, captureDevice, configuration, communication)
})
// This is legacy should be removed in future! Now everything
// lives under the /api prefix.
r.POST("/config", func(c *gin.Context) {
var config models.Config
err := c.BindJSON(&config)
if err == nil {
err := configService.SaveConfig(configDirectory, config, configuration, communication)
if err == nil {
c.JSON(200, gin.H{
"data": "☄ Reconfiguring",
})
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
components.UpdateConfig(c, configDirectory, configuration, communication)
})
api := r.Group("/api")
@@ -66,133 +35,44 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirect
api.POST("/login", authMiddleware.LoginHandler)
api.GET("/dashboard", func(c *gin.Context) {
// Check if camera is online.
cameraIsOnline := communication.CameraConnected
// If an agent is properly setup with Kerberos Hub, we will send
// a ping to Kerberos Hub every 15seconds. On receiving a positive response
// it will update the CloudTimestamp value.
cloudIsOnline := false
if communication.CloudTimestamp != nil && communication.CloudTimestamp.Load() != nil {
timestamp := communication.CloudTimestamp.Load().(int64)
if timestamp > 0 {
cloudIsOnline = true
}
}
// The total number of recordings stored in the directory.
recordingDirectory := configDirectory + "/data/recordings"
numberOfRecordings := utils.NumberOfMP4sInDirectory(recordingDirectory)
// All days stored in this agent.
days := []string{}
latestEvents := []models.Media{}
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
// Get All days
days = utils.GetDays(events, recordingDirectory, configuration)
// Get all latest events
var eventFilter models.EventFilter
eventFilter.NumberOfElements = 5
latestEvents = utils.GetMediaFormatted(events, recordingDirectory, configuration, eventFilter) // will get 5 latest recordings.
}
c.JSON(200, gin.H{
"offlineMode": configuration.Config.Offline,
"cameraOnline": cameraIsOnline,
"cloudOnline": cloudIsOnline,
"numberOfRecordings": numberOfRecordings,
"days": days,
"latestEvents": latestEvents,
})
components.GetDashboard(c, configDirectory, configuration, communication)
})
api.POST("/latest-events", func(c *gin.Context) {
var eventFilter models.EventFilter
err := c.BindJSON(&eventFilter)
if err == nil {
// Default to 10 if no limit is set.
if eventFilter.NumberOfElements == 0 {
eventFilter.NumberOfElements = 10
}
recordingDirectory := configDirectory + "/data/recordings"
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
// We will get all recordings from the directory (as defined by the filter).
fileObjects := utils.GetMediaFormatted(events, recordingDirectory, configuration, eventFilter)
c.JSON(200, gin.H{
"events": fileObjects,
})
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
components.GetLatestEvents(c, configDirectory, configuration, communication)
})
api.GET("/days", func(c *gin.Context) {
recordingDirectory := configDirectory + "/data/recordings"
files, err := utils.ReadDirectory(recordingDirectory)
if err == nil {
events := utils.GetSortedDirectory(files)
days := utils.GetDays(events, recordingDirectory, configuration)
c.JSON(200, gin.H{
"events": days,
})
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
})
}
components.GetDays(c, configDirectory, configuration, communication)
})
api.GET("/config", func(c *gin.Context) {
// We'll try to get a snapshot from the camera.
base64Image := capture.Base64Image(captureDevice, communication)
if base64Image != "" {
communication.Image = base64Image
}
c.JSON(200, gin.H{
"config": configuration.Config,
"custom": configuration.CustomConfig,
"global": configuration.GlobalConfig,
"snapshot": communication.Image,
})
components.GetConfig(c, captureDevice, configuration, communication)
})
api.POST("/config", func(c *gin.Context) {
var config models.Config
err := c.BindJSON(&config)
if err == nil {
err := configService.SaveConfig(configDirectory, config, configuration, communication)
if err == nil {
c.JSON(200, gin.H{
"data": "☄ Reconfiguring",
components.UpdateConfig(c, configDirectory, configuration, communication)
})
} else {
c.JSON(200, gin.H{
"data": "☄ Reconfiguring",
// Will verify the current onvif settings.
api.POST("/onvif/verify", func(c *gin.Context) {
onvif.VerifyOnvifConnection(c)
})
}
} else {
c.JSON(400, gin.H{
"data": "Something went wrong: " + err.Error(),
// Will verify the current hub settings.
api.POST("/hub/verify", func(c *gin.Context) {
cloud.VerifyHub(c)
})
}
// Will verify the current persistence settings.
api.POST("/persistence/verify", func(c *gin.Context) {
cloud.VerifyPersistence(c, configDirectory)
})
// Camera specific methods. Doesn't require any authorization.
// These are available for anyone, but require the agent, to reach
// the camera.
api.POST("/camera/restart", func(c *gin.Context) {
components.RestartAgent(c, communication)
})
@@ -205,21 +85,6 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirect
components.MakeRecording(c, communication)
})
api.POST("/onvif/verify", func(c *gin.Context) {
onvif.VerifyOnvifConnection(c)
})
api.POST("/hub/verify", func(c *gin.Context) {
cloud.VerifyHub(c)
})
api.POST("/persistence/verify", func(c *gin.Context) {
cloud.VerifyPersistence(c, configDirectory)
})
// Camera specific methods. Doesn't require any authorization.
// These are available for anyone, but require the agent, to reach
// the camera.
api.POST("/camera/onvif/login", LoginToOnvif)
api.POST("/camera/onvif/capabilities", GetOnvifCapabilities)
api.POST("/camera/onvif/presets", GetOnvifPresets)