add onvif verify option + improve streaming logic + reconnect websocket

This commit is contained in:
Cedric Verstraeten
2023-06-12 20:33:41 +02:00
parent 9cf9babd73
commit 60e8edc876
26 changed files with 559 additions and 90 deletions

View File

@@ -244,6 +244,40 @@ const docTemplate = `{
} }
} }
}, },
"/api/onvif/verify": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "Will verify the ONVIF connectivity.",
"tags": [
"config"
],
"summary": "Will verify the ONVIF connectivity.",
"operationId": "verify-onvif",
"parameters": [
{
"description": "Camera Config",
"name": "cameraConfig",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.IPCamera"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.APIResponse"
}
}
}
}
},
"/api/persistence/verify": { "/api/persistence/verify": {
"post": { "post": {
"security": [ "security": [
@@ -347,9 +381,15 @@ const docTemplate = `{
"ipcamera": { "ipcamera": {
"$ref": "#/definitions/models.IPCamera" "$ref": "#/definitions/models.IPCamera"
}, },
"liveview": {
"type": "string"
},
"maxlengthrecording": { "maxlengthrecording": {
"type": "integer" "type": "integer"
}, },
"motion": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@@ -365,6 +405,12 @@ const docTemplate = `{
"raspicamera": { "raspicamera": {
"$ref": "#/definitions/models.RaspiCamera" "$ref": "#/definitions/models.RaspiCamera"
}, },
"recording": {
"type": "string"
},
"snapshots": {
"type": "string"
},
"transcodingresolution": { "transcodingresolution": {
"type": "integer" "type": "integer"
}, },
@@ -391,6 +437,12 @@ const docTemplate = `{
"condition_uri": { "condition_uri": {
"type": "string" "type": "string"
}, },
"dropbox": {
"$ref": "#/definitions/models.Dropbox"
},
"friendly_name": {
"type": "string"
},
"heartbeaturi": { "heartbeaturi": {
"description": "obsolete", "description": "obsolete",
"type": "string" "type": "string"
@@ -434,6 +486,9 @@ const docTemplate = `{
"region": { "region": {
"$ref": "#/definitions/models.Region" "$ref": "#/definitions/models.Region"
}, },
"remove_after_upload": {
"type": "string"
},
"s3": { "s3": {
"$ref": "#/definitions/models.S3" "$ref": "#/definitions/models.S3"
}, },
@@ -477,6 +532,17 @@ const docTemplate = `{
} }
} }
}, },
"models.Dropbox": {
"type": "object",
"properties": {
"access_token": {
"type": "string"
},
"directory": {
"type": "string"
}
}
},
"models.IPCamera": { "models.IPCamera": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -484,7 +550,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"onvif": { "onvif": {
"type": "boolean" "type": "string"
}, },
"onvif_password": { "onvif_password": {
"type": "string" "type": "string"

View File

@@ -236,6 +236,40 @@
} }
} }
}, },
"/api/onvif/verify": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "Will verify the ONVIF connectivity.",
"tags": [
"config"
],
"summary": "Will verify the ONVIF connectivity.",
"operationId": "verify-onvif",
"parameters": [
{
"description": "Camera Config",
"name": "cameraConfig",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.IPCamera"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.APIResponse"
}
}
}
}
},
"/api/persistence/verify": { "/api/persistence/verify": {
"post": { "post": {
"security": [ "security": [
@@ -339,9 +373,15 @@
"ipcamera": { "ipcamera": {
"$ref": "#/definitions/models.IPCamera" "$ref": "#/definitions/models.IPCamera"
}, },
"liveview": {
"type": "string"
},
"maxlengthrecording": { "maxlengthrecording": {
"type": "integer" "type": "integer"
}, },
"motion": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@@ -357,6 +397,12 @@
"raspicamera": { "raspicamera": {
"$ref": "#/definitions/models.RaspiCamera" "$ref": "#/definitions/models.RaspiCamera"
}, },
"recording": {
"type": "string"
},
"snapshots": {
"type": "string"
},
"transcodingresolution": { "transcodingresolution": {
"type": "integer" "type": "integer"
}, },
@@ -383,6 +429,12 @@
"condition_uri": { "condition_uri": {
"type": "string" "type": "string"
}, },
"dropbox": {
"$ref": "#/definitions/models.Dropbox"
},
"friendly_name": {
"type": "string"
},
"heartbeaturi": { "heartbeaturi": {
"description": "obsolete", "description": "obsolete",
"type": "string" "type": "string"
@@ -426,6 +478,9 @@
"region": { "region": {
"$ref": "#/definitions/models.Region" "$ref": "#/definitions/models.Region"
}, },
"remove_after_upload": {
"type": "string"
},
"s3": { "s3": {
"$ref": "#/definitions/models.S3" "$ref": "#/definitions/models.S3"
}, },
@@ -469,6 +524,17 @@
} }
} }
}, },
"models.Dropbox": {
"type": "object",
"properties": {
"access_token": {
"type": "string"
},
"directory": {
"type": "string"
}
}
},
"models.IPCamera": { "models.IPCamera": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -476,7 +542,7 @@
"type": "string" "type": "string"
}, },
"onvif": { "onvif": {
"type": "boolean" "type": "string"
}, },
"onvif_password": { "onvif_password": {
"type": "string" "type": "string"

View File

@@ -44,8 +44,12 @@ definitions:
type: integer type: integer
ipcamera: ipcamera:
$ref: '#/definitions/models.IPCamera' $ref: '#/definitions/models.IPCamera'
liveview:
type: string
maxlengthrecording: maxlengthrecording:
type: integer type: integer
motion:
type: string
name: name:
type: string type: string
pixelChangeThreshold: pixelChangeThreshold:
@@ -56,6 +60,10 @@ definitions:
type: integer type: integer
raspicamera: raspicamera:
$ref: '#/definitions/models.RaspiCamera' $ref: '#/definitions/models.RaspiCamera'
recording:
type: string
snapshots:
type: string
transcodingresolution: transcodingresolution:
type: integer type: integer
transcodingwebrtc: transcodingwebrtc:
@@ -73,6 +81,10 @@ definitions:
type: string type: string
condition_uri: condition_uri:
type: string type: string
dropbox:
$ref: '#/definitions/models.Dropbox'
friendly_name:
type: string
heartbeaturi: heartbeaturi:
description: obsolete description: obsolete
type: string type: string
@@ -102,6 +114,8 @@ definitions:
type: string type: string
region: region:
$ref: '#/definitions/models.Region' $ref: '#/definitions/models.Region'
remove_after_upload:
type: string
s3: s3:
$ref: '#/definitions/models.S3' $ref: '#/definitions/models.S3'
stunuri: stunuri:
@@ -130,12 +144,19 @@ definitions:
"y": "y":
type: number type: number
type: object type: object
models.Dropbox:
properties:
access_token:
type: string
directory:
type: string
type: object
models.IPCamera: models.IPCamera:
properties: properties:
fps: fps:
type: string type: string
onvif: onvif:
type: boolean type: string
onvif_password: onvif_password:
type: string type: string
onvif_username: onvif_username:
@@ -414,6 +435,27 @@ paths:
summary: Get Authorization token. summary: Get Authorization token.
tags: tags:
- authentication - authentication
/api/onvif/verify:
post:
description: Will verify the ONVIF connectivity.
operationId: verify-onvif
parameters:
- description: Camera Config
in: body
name: cameraConfig
required: true
schema:
$ref: '#/definitions/models.IPCamera'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/models.APIResponse'
security:
- Bearer: []
summary: Will verify the ONVIF connectivity.
tags:
- config
/api/persistence/verify: /api/persistence/verify:
post: post:
description: Will verify the persistence. description: Will verify the persistence.

View File

@@ -273,7 +273,8 @@ loop:
// We'll check which mode is enabled for the camera. // We'll check which mode is enabled for the camera.
onvifEnabled := "false" onvifEnabled := "false"
if config.Capture.IPCamera.ONVIFXAddr != "" { if config.Capture.IPCamera.ONVIFXAddr != "" {
device, err := onvif.ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
capabilities := onvif.GetCapabilitiesFromDevice(device) capabilities := onvif.GetCapabilitiesFromDevice(device)
for _, v := range capabilities { for _, v := range capabilities {

View File

@@ -85,9 +85,6 @@ func Bootstrap(configuration *models.Configuration, communication *models.Commun
break break
} }
// We will reconfigure or restart the agent, we will mark the agent as not connected.
communication.CameraConnected = false
// We will re open the configuration, might have changed :O! // We will re open the configuration, might have changed :O!
OpenConfig(configuration) OpenConfig(configuration)
@@ -224,9 +221,6 @@ func RunAgent(configuration *models.Configuration, communication *models.Communi
subQueue.WriteHeader(subStreams) subQueue.WriteHeader(subStreams)
} }
// If we reach this point, we have a working RTSP connection.
communication.CameraConnected = true
// Handle the camera stream // Handle the camera stream
go capture.HandleStream(infile, queue, communication) go capture.HandleStream(infile, queue, communication)
@@ -273,12 +267,18 @@ func RunAgent(configuration *models.Configuration, communication *models.Communi
// Handle ONVIF actions // Handle ONVIF actions
go onvif.HandleONVIFActions(configuration, communication) go onvif.HandleONVIFActions(configuration, communication)
// If we reach this point, we have a working RTSP connection.
communication.CameraConnected = true
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This will go into a blocking state, once this channel is triggered // This will go into a blocking state, once this channel is triggered
// the agent will cleanup and restart. // the agent will cleanup and restart.
status = <-communication.HandleBootstrap status = <-communication.HandleBootstrap
// If we reach this point, we are stopping the stream.
communication.CameraConnected = false
// Cancel the main context, this will stop all the other goroutines. // Cancel the main context, this will stop all the other goroutines.
(*communication.CancelContext)() (*communication.CancelContext)()

View File

@@ -1,8 +1,11 @@
package models package models
type APIResponse struct { type APIResponse struct {
Data interface{} `json:"data" bson:"data"` Data interface{} `json:"data" bson:"data"`
Message interface{} `json:"message" bson:"message"` Message interface{} `json:"message" bson:"message"`
PTZFunctions interface{} `json:"ptz_functions" bson:"ptz_functions"`
CanZoom bool `json:"can_zoom" bson:"can_zoom"`
CanPanTilt bool `json:"can_pan_tilt" bson:"can_pan_tilt"`
} }
type OnvifCredentials struct { type OnvifCredentials struct {

View File

@@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/kerberos-io/agent/machinery/src/log" "github.com/kerberos-io/agent/machinery/src/log"
"github.com/kerberos-io/agent/machinery/src/models" "github.com/kerberos-io/agent/machinery/src/models"
"github.com/kerberos-io/onvif/media" "github.com/kerberos-io/onvif/media"
@@ -31,7 +32,8 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode
json.Unmarshal(b, &ptzAction) json.Unmarshal(b, &ptzAction)
// Connect to Onvif device // Connect to Onvif device
device, err := ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
// Get token from the first profile // Get token from the first profile
@@ -39,7 +41,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode
if err == nil { if err == nil {
// Get the configurations from the device // Get the configurations from the device
configurations, err := GetConfigurationsFromDevice(device) configurations, err := GetPTZConfigurationsFromDevice(device)
if err == nil { if err == nil {
@@ -100,16 +102,13 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode
log.Log.Debug("HandleONVIFActions: finished") log.Log.Debug("HandleONVIFActions: finished")
} }
func ConnectToOnvifDevice(configuration *models.Configuration) (*onvif.Device, error) { func ConnectToOnvifDevice(cameraConfiguration *models.IPCamera) (*onvif.Device, error) {
log.Log.Debug("ConnectToOnvifDevice: started") log.Log.Debug("ConnectToOnvifDevice: started")
config := configuration.Config
// Get the capabilities of the ONVIF device
device, err := onvif.NewDevice(onvif.DeviceParams{ device, err := onvif.NewDevice(onvif.DeviceParams{
Xaddr: config.Capture.IPCamera.ONVIFXAddr, Xaddr: cameraConfiguration.ONVIFXAddr,
Username: config.Capture.IPCamera.ONVIFUsername, Username: cameraConfiguration.ONVIFUsername,
Password: config.Capture.IPCamera.ONVIFPassword, Password: cameraConfiguration.ONVIFPassword,
}) })
if err != nil { if err != nil {
@@ -154,11 +153,11 @@ func GetTokenFromProfile(device *onvif.Device, profileId int) (xsd.ReferenceToke
return profileToken, err return profileToken, err
} }
func GetConfigurationsFromDevice(device *onvif.Device) (ptz.GetConfigurationsResponse, error) { func GetPTZConfigurationsFromDevice(device *onvif.Device) (ptz.GetConfigurationsResponse, error) {
// We'll try to receive the PTZ configurations from the server // We'll try to receive the PTZ configurations from the server
var configurations ptz.GetConfigurationsResponse var configurations ptz.GetConfigurationsResponse
// Get the configurations from the device // Get the PTZ configurations from the device
resp, err := device.CallMethod(ptz.GetConfigurations{}) resp, err := device.CallMethod(ptz.GetConfigurations{})
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
@@ -167,11 +166,11 @@ func GetConfigurationsFromDevice(device *onvif.Device) (ptz.GetConfigurationsRes
stringBody := string(b) stringBody := string(b)
decodedXML, et, err := getXMLNode(stringBody, "GetConfigurationsResponse") decodedXML, et, err := getXMLNode(stringBody, "GetConfigurationsResponse")
if err != nil { if err != nil {
log.Log.Error("GetConfigurationsFromDevice: " + err.Error()) log.Log.Error("GetPTZConfigurationsFromDevice: " + err.Error())
return configurations, err return configurations, err
} else { } else {
if err := decodedXML.DecodeElement(&configurations, et); err != nil { if err := decodedXML.DecodeElement(&configurations, et); err != nil {
log.Log.Error("GetConfigurationsFromDevice: " + err.Error()) log.Log.Error("GetPTZConfigurationsFromDevice: " + err.Error())
return configurations, err return configurations, err
} }
} }
@@ -317,3 +316,89 @@ func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElemen
} }
return nil, nil, errors.New("error in NodeName - username and password might be wrong") return nil, nil, errors.New("error in NodeName - username and password might be wrong")
} }
func GetPTZFunctionsFromDevice(configurations ptz.GetConfigurationsResponse) ([]string, bool, bool) {
var functions []string
canZoom := false
canPanTilt := false
if configurations.PTZConfiguration.DefaultAbsolutePantTiltPositionSpace != "" {
functions = append(functions, "AbsolutePanTiltMove")
canPanTilt = true
}
if configurations.PTZConfiguration.DefaultAbsoluteZoomPositionSpace != "" {
functions = append(functions, "AbsoluteZoomMove")
canZoom = true
}
if configurations.PTZConfiguration.DefaultRelativePanTiltTranslationSpace != "" {
functions = append(functions, "RelativePanTiltMove")
canPanTilt = true
}
if configurations.PTZConfiguration.DefaultRelativeZoomTranslationSpace != "" {
functions = append(functions, "RelativeZoomMove")
canZoom = true
}
if configurations.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace != "" {
functions = append(functions, "ContinuousPanTiltMove")
canPanTilt = true
}
if configurations.PTZConfiguration.DefaultContinuousZoomVelocitySpace != "" {
functions = append(functions, "ContinuousZoomMove")
canZoom = true
}
if configurations.PTZConfiguration.DefaultPTZSpeed != nil {
functions = append(functions, "PTZSpeed")
}
if configurations.PTZConfiguration.DefaultPTZTimeout != "" {
functions = append(functions, "PTZTimeout")
}
return functions, canZoom, canPanTilt
}
// VerifyOnvifConnection godoc
// @Router /api/onvif/verify [post]
// @ID verify-onvif
// @Security Bearer
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @Tags config
// @Param cameraConfig body models.IPCamera true "Camera Config"
// @Summary Will verify the ONVIF connectivity.
// @Description Will verify the ONVIF connectivity.
// @Success 200 {object} models.APIResponse
func VerifyOnvifConnection(c *gin.Context) {
var cameraConfig models.IPCamera
err := c.BindJSON(&cameraConfig)
if err == nil {
device, err := ConnectToOnvifDevice(&cameraConfig)
if err == nil {
// Get the list of configurations
configurations, err := GetPTZConfigurationsFromDevice(device)
if err == nil {
// Check if can zoom and/or pan/tilt is supported
ptzFunctions, canZoom, canPanTilt := GetPTZFunctionsFromDevice(configurations)
c.JSON(200, models.APIResponse{
Data: device,
PTZFunctions: ptzFunctions,
CanZoom: canZoom,
CanPanTilt: canPanTilt,
})
} else {
c.JSON(400, models.APIResponse{
Message: "Something went wrong while getting the configurations " + err.Error(),
})
}
} else {
c.JSON(400, models.APIResponse{
Message: "Something went wrong while verifying the ONVIF connection " + err.Error(),
})
}
} else {
c.JSON(400, models.APIResponse{
Message: "Something went wrong while receiving the config " + err.Error(),
})
}
}

View File

@@ -42,7 +42,8 @@ func LoginToOnvif(c *gin.Context) {
}, },
} }
device, err := onvif.ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
c.JSON(200, gin.H{ c.JSON(200, gin.H{
"device": device, "device": device,
@@ -85,7 +86,8 @@ func GetOnvifCapabilities(c *gin.Context) {
}, },
} }
device, err := onvif.ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
c.JSON(200, gin.H{ c.JSON(200, gin.H{
"capabilities": onvif.GetCapabilitiesFromDevice(device), "capabilities": onvif.GetCapabilitiesFromDevice(device),
@@ -128,7 +130,8 @@ func DoOnvifPanTilt(c *gin.Context) {
}, },
} }
device, err := onvif.ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
// Get token from the first profile // Get token from the first profile
@@ -137,13 +140,13 @@ func DoOnvifPanTilt(c *gin.Context) {
if err == nil { if err == nil {
// Get the configurations from the device // Get the configurations from the device
configurations, err := onvif.GetConfigurationsFromDevice(device) ptzConfigurations, err := onvif.GetPTZConfigurationsFromDevice(device)
if err == nil { if err == nil {
pan := onvifPanTilt.Pan pan := onvifPanTilt.Pan
tilt := onvifPanTilt.Tilt tilt := onvifPanTilt.Tilt
err := onvif.ContinuousPanTilt(device, configurations, token, pan, tilt) err := onvif.ContinuousPanTilt(device, ptzConfigurations, token, pan, tilt)
if err == nil { if err == nil {
c.JSON(200, models.APIResponse{ c.JSON(200, models.APIResponse{
Message: "Successfully pan/tilted the camera", Message: "Successfully pan/tilted the camera",
@@ -201,7 +204,8 @@ func DoOnvifZoom(c *gin.Context) {
}, },
} }
device, err := onvif.ConnectToOnvifDevice(configuration) cameraConfiguration := configuration.Config.Capture.IPCamera
device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil { if err == nil {
// Get token from the first profile // Get token from the first profile
@@ -209,13 +213,13 @@ func DoOnvifZoom(c *gin.Context) {
if err == nil { if err == nil {
// Get the configurations from the device // Get the PTZ configurations from the device
configurations, err := onvif.GetConfigurationsFromDevice(device) ptzConfigurations, err := onvif.GetPTZConfigurationsFromDevice(device)
if err == nil { if err == nil {
zoom := onvifZoom.Zoom zoom := onvifZoom.Zoom
err := onvif.ContinuousZoom(device, configurations, token, zoom) err := onvif.ContinuousZoom(device, ptzConfigurations, token, zoom)
if err == nil { if err == nil {
c.JSON(200, models.APIResponse{ c.JSON(200, models.APIResponse{
Message: "Successfully zoomed the camera", Message: "Successfully zoomed the camera",

View File

@@ -7,6 +7,7 @@ import (
jwt "github.com/appleboy/gin-jwt/v2" jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/kerberos-io/agent/machinery/src/capture" "github.com/kerberos-io/agent/machinery/src/capture"
"github.com/kerberos-io/agent/machinery/src/onvif"
"github.com/kerberos-io/agent/machinery/src/routers/websocket" "github.com/kerberos-io/agent/machinery/src/routers/websocket"
"github.com/kerberos-io/agent/machinery/src/cloud" "github.com/kerberos-io/agent/machinery/src/cloud"
@@ -196,6 +197,10 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
}) })
}) })
api.POST("/onvif/verify", func(c *gin.Context) {
onvif.VerifyOnvifConnection(c)
})
api.POST("/hub/verify", func(c *gin.Context) { api.POST("/hub/verify", func(c *gin.Context) {
cloud.VerifyHub(c) cloud.VerifyHub(c)
}) })

View File

@@ -51,6 +51,7 @@ func WebsocketHandler(c *gin.Context, communication *models.Communication) {
w := c.Writer w := c.Writer
r := c.Request r := c.Request
conn, err := upgrader.Upgrade(w, r, nil) conn, err := upgrader.Upgrade(w, r, nil)
// error handling here // error handling here
if err == nil { if err == nil {
defer conn.Close() defer conn.Close()
@@ -83,28 +84,29 @@ func WebsocketHandler(c *gin.Context, communication *models.Communication) {
_, exists := sockets[clientID].Cancels["stream-sd"] _, exists := sockets[clientID].Cancels["stream-sd"]
if exists { if exists {
sockets[clientID].Cancels["stream-sd"]() sockets[clientID].Cancels["stream-sd"]()
delete(sockets[clientID].Cancels, "stream-sd")
} else { } else {
log.Log.Error("Streaming sd does not exists for " + clientID) log.Log.Error("Streaming sd does not exists for " + clientID)
} }
case "stream-sd": case "stream-sd":
startStrean := Message{ if communication.CameraConnected {
ClientID: clientID, _, exists := sockets[clientID].Cancels["stream-sd"]
MessageType: "stream-sd", if exists {
Message: map[string]string{ log.Log.Info("Already streaming sd for " + clientID)
"message": "Start streaming low resolution", } else {
}, startStream := Message{
} ClientID: clientID,
sockets[clientID].WriteJson(startStrean) MessageType: "stream-sd",
Message: map[string]string{
"message": "Start streaming low resolution",
},
}
sockets[clientID].WriteJson(startStream)
_, exists := sockets[clientID].Cancels["stream-sd"] ctx, cancel := context.WithCancel(context.Background())
if exists { sockets[clientID].Cancels["stream-sd"] = cancel
log.Log.Info("Already streaming sd for " + clientID) go ForwardSDStream(ctx, clientID, sockets[clientID], communication)
} else { }
ctx, cancel := context.WithCancel(context.Background())
sockets[clientID].Cancels["stream-sd"] = cancel
go ForwardSDStream(ctx, clientID, sockets[clientID], communication)
} }
} }
@@ -173,5 +175,14 @@ logreader:
frame.Free() frame.Free()
// Close socket for streaming
_, exists := connection.Cancels["stream-sd"]
if exists {
delete(connection.Cancels, "stream-sd")
} else {
log.Log.Error("Streaming sd does not exists for " + clientID)
}
// Send stop streaming message
log.Log.Info("ForwardSDStream: stop sending streaming over websocket") log.Log.Info("ForwardSDStream: stop sending streaming over websocket")
} }

View File

@@ -4,7 +4,7 @@
"private": false, "private": false,
"dependencies": { "dependencies": {
"@giantmachines/redux-websocket": "^1.5.1", "@giantmachines/redux-websocket": "^1.5.1",
"@kerberos-io/ui": "^1.72.0", "@kerberos-io/ui": "^1.76.0",
"@material-ui/core": "^4.12.4", "@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.3", "@material-ui/icons": "^4.11.3",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",

View File

@@ -4,7 +4,8 @@
"configure": "Konfigurieren" "configure": "Konfigurieren"
}, },
"buttons": { "buttons": {
"save": "Speichern" "save": "Speichern",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "Profil", "profile": "Profil",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Beim überprüfen der Speichereinstellungen ist ein Fehler aufgetreten", "verify_persistence_error": "Beim überprüfen der Speichereinstellungen ist ein Fehler aufgetreten",
"verify_camera": "Überprüfen der Kameraeinstellungen.", "verify_camera": "Überprüfen der Kameraeinstellungen.",
"verify_camera_success": "Die Kameraeinstellungen wurden erfolgreich überprüft.", "verify_camera_success": "Die Kameraeinstellungen wurden erfolgreich überprüft.",
"verify_camera_error": "Beim überprüfen der Kameraeinstellungen ist ein Fehler aufgetreten" "verify_camera_error": "Beim überprüfen der Kameraeinstellungen ist ein Fehler aufgetreten",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "Allgemein", "general": "Allgemein",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "Die Region in der die Aufnahmen gespeichert werden sollen.", "kerberoshub_description_region": "Die Region in der die Aufnahmen gespeichert werden sollen.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "Der Bucket in dem die Aufnahmen gespeichert werden.", "kerberoshub_description_bucket": "Der Bucket in dem die Aufnahmen gespeichert werden.",
"kerberoshub_username": "Benutzername/Verzeichnis", "kerberoshub_username": "Benutzername/Verzeichnis (should match Kerberos Hub username)",
"kerberoshub_description_username": "Der Benutzername des Kerberos Hub Accounts.", "kerberoshub_description_username": "Der Benutzername des Kerberos Hub Accounts.",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "Die Kerberos Vault API URL.", "kerberosvault_description_apiurl": "Die Kerberos Vault API URL.",
"kerberosvault_provider": "Anbieter", "kerberosvault_provider": "Anbieter",
"kerberosvault_description_provider": "Der Anbieter zu dem die Aufnahmen gesendet werden.", "kerberosvault_description_provider": "Der Anbieter zu dem die Aufnahmen gesendet werden.",
"kerberosvault_directory": "Verzeichnis", "kerberosvault_directory": "Verzeichnis (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Das Uneterverzeichnis in dem die Aufnahmen gespeichert werden sollen.", "kerberosvault_description_directory": "Das Uneterverzeichnis in dem die Aufnahmen gespeichert werden sollen.",
"kerberosvault_accesskey": "Zugriffsschlüssel", "kerberosvault_accesskey": "Zugriffsschlüssel",
"kerberosvault_description_accesskey": "Der Zugriffsschlüssel des Kerberos Vault Accounts..", "kerberosvault_description_accesskey": "Der Zugriffsschlüssel des Kerberos Vault Accounts..",

View File

@@ -4,7 +4,8 @@
"configure": "Configure" "configure": "Configure"
}, },
"buttons": { "buttons": {
"save": "Save" "save": "Save",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "Profile", "profile": "Profile",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Something went wrong while verifying the persistence", "verify_persistence_error": "Something went wrong while verifying the persistence",
"verify_camera": "Verifying your camera settings.", "verify_camera": "Verifying your camera settings.",
"verify_camera_success": "Camera settings are successfully verified.", "verify_camera_success": "Camera settings are successfully verified.",
"verify_camera_error": "Something went wrong while verifying the camera settings" "verify_camera_error": "Something went wrong while verifying the camera settings",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "General", "general": "General",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "The region we are storing our recordings in.", "kerberoshub_description_region": "The region we are storing our recordings in.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "The bucket we are storing our recordings in.", "kerberoshub_description_bucket": "The bucket we are storing our recordings in.",
"kerberoshub_username": "Username/Directory", "kerberoshub_username": "Username/Directory (should match Kerberos Hub username)",
"kerberoshub_description_username": "The username of your Kerberos Hub account.", "kerberoshub_description_username": "The username of your Kerberos Hub account.",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "The Kerberos Vault API", "kerberosvault_description_apiurl": "The Kerberos Vault API",
"kerberosvault_provider": "Provider", "kerberosvault_provider": "Provider",
"kerberosvault_description_provider": "The provider to which your recordings will be send.", "kerberosvault_description_provider": "The provider to which your recordings will be send.",
"kerberosvault_directory": "Directory", "kerberosvault_directory": "Directory (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.", "kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.",
"kerberosvault_accesskey": "Access key", "kerberosvault_accesskey": "Access key",
"kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.", "kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.",

View File

@@ -4,7 +4,8 @@
"configure": "Configure" "configure": "Configure"
}, },
"buttons": { "buttons": {
"save": "Save" "save": "Save",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "Perfil", "profile": "Perfil",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Something went wrong while verifying the persistence", "verify_persistence_error": "Something went wrong while verifying the persistence",
"verify_camera": "Verifying your camera settings.", "verify_camera": "Verifying your camera settings.",
"verify_camera_success": "Camera settings are successfully verified.", "verify_camera_success": "Camera settings are successfully verified.",
"verify_camera_error": "Something went wrong while verifying the camera settings" "verify_camera_error": "Something went wrong while verifying the camera settings",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "General", "general": "General",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "The region we are storing our recordings in.", "kerberoshub_description_region": "The region we are storing our recordings in.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "The bucket we are storing our recordings in.", "kerberoshub_description_bucket": "The bucket we are storing our recordings in.",
"kerberoshub_username": "Username/Directory", "kerberoshub_username": "Username/Directory (should match Kerberos Hub username)",
"kerberoshub_description_username": "The username of your Kerberos Hub account.", "kerberoshub_description_username": "The username of your Kerberos Hub account.",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "The Kerberos Vault API", "kerberosvault_description_apiurl": "The Kerberos Vault API",
"kerberosvault_provider": "Provider", "kerberosvault_provider": "Provider",
"kerberosvault_description_provider": "The provider to which your recordings will be send.", "kerberosvault_description_provider": "The provider to which your recordings will be send.",
"kerberosvault_directory": "Directory", "kerberosvault_directory": "Directory (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.", "kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.",
"kerberosvault_accesskey": "Access key", "kerberosvault_accesskey": "Access key",
"kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.", "kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.",

View File

@@ -69,7 +69,10 @@
"verify_persistence_error": "Quelque chose s'est mal déroulé lors de la vérification de la persistance", "verify_persistence_error": "Quelque chose s'est mal déroulé lors de la vérification de la persistance",
"verify_camera": "Vérifier les paramètres de votre caméra.", "verify_camera": "Vérifier les paramètres de votre caméra.",
"verify_camera_success": "Les paramètres de la caméra sont vérifiés avec succès.", "verify_camera_success": "Les paramètres de la caméra sont vérifiés avec succès.",
"verify_camera_error": "Quelque chose s'est mal déroulé lors de la vérification des paramètres de la caméra" "verify_camera_error": "Quelque chose s'est mal déroulé lors de la vérification des paramètres de la caméra",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "Général", "general": "Général",
@@ -186,13 +189,13 @@
"kerberoshub_description_region": "La région dans laquelle nous stockons vos enregistrements.", "kerberoshub_description_region": "La région dans laquelle nous stockons vos enregistrements.",
"kerberoshub_bucket": "Compartiment", "kerberoshub_bucket": "Compartiment",
"kerberoshub_description_bucket": "Le compartiment dans lequel nous stockons vos enregistrements.", "kerberoshub_description_bucket": "Le compartiment dans lequel nous stockons vos enregistrements.",
"kerberoshub_username": "Utilisateur/Répertoire", "kerberoshub_username": "Utilisateur/Répertoire (should match Kerberos Hub username)",
"kerberoshub_description_username": "Le nom d'utilisateur de votre compte Kerberos Hub.", "kerberoshub_description_username": "Le nom d'utilisateur de votre compte Kerberos Hub.",
"kerberosvault_apiurl": "URL de l'API Kerberos Vault", "kerberosvault_apiurl": "URL de l'API Kerberos Vault",
"kerberosvault_description_apiurl": "L'API Kerberos Vault", "kerberosvault_description_apiurl": "L'API Kerberos Vault",
"kerberosvault_provider": "Fournisseur", "kerberosvault_provider": "Fournisseur",
"kerberosvault_description_provider": "Le fournisseur auquel vos enregistrements seront envoyés.", "kerberosvault_description_provider": "Le fournisseur auquel vos enregistrements seront envoyés.",
"kerberosvault_directory": "Répertoire", "kerberosvault_directory": "Répertoire (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Le sous-répertoire dans lequel les enregistrements seront stockés chez votre fournisseur.", "kerberosvault_description_directory": "Le sous-répertoire dans lequel les enregistrements seront stockés chez votre fournisseur.",
"kerberosvault_accesskey": "Clé d'accès", "kerberosvault_accesskey": "Clé d'accès",
"kerberosvault_description_accesskey": "La clé d'accès de votre compte Kerberos Vault.", "kerberosvault_description_accesskey": "La clé d'accès de votre compte Kerberos Vault.",

View File

@@ -4,7 +4,8 @@
"configure": "設定" "configure": "設定"
}, },
"buttons": { "buttons": {
"save": "保存" "save": "保存",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "プロフィール", "profile": "プロフィール",
@@ -69,7 +70,10 @@
"verify_persistence_error": "持続性の検証中に問題が発生しました", "verify_persistence_error": "持続性の検証中に問題が発生しました",
"verify_camera": "カメラの設定を確認しています。", "verify_camera": "カメラの設定を確認しています。",
"verify_camera_success": "カメラの設定が正常に検証されました。", "verify_camera_success": "カメラの設定が正常に検証されました。",
"verify_camera_error": "カメラ設定の確認中に問題が発生しました" "verify_camera_error": "カメラ設定の確認中に問題が発生しました",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "全般的", "general": "全般的",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "録音を保存しているリージョン。", "kerberoshub_description_region": "録音を保存しているリージョン。",
"kerberoshub_bucket": "bucket", "kerberoshub_bucket": "bucket",
"kerberoshub_description_bucket": "録音を保存しているbucket", "kerberoshub_description_bucket": "録音を保存しているbucket",
"kerberoshub_username": "ユーザー名/ディレクトリ", "kerberoshub_username": "ユーザー名/ディレクトリ (should match Kerberos Hub username)",
"kerberoshub_description_username": "Kerberos Hub アカウントのユーザー名。", "kerberoshub_description_username": "Kerberos Hub アカウントのユーザー名。",
"kerberosvault_apiurl": "Kerberos ボールト API URL", "kerberosvault_apiurl": "Kerberos ボールト API URL",
"kerberosvault_description_apiurl": "Kerberos ボールト API", "kerberosvault_description_apiurl": "Kerberos ボールト API",
"kerberosvault_provider": "プロバイダ", "kerberosvault_provider": "プロバイダ",
"kerberosvault_description_provider": "録音の送信先のプロバイダー。", "kerberosvault_description_provider": "録音の送信先のプロバイダー。",
"kerberosvault_directory": "ディレクトリ", "kerberosvault_directory": "ディレクトリ (should match Kerberos Hub username)",
"kerberosvault_description_directory": "録音がプロバイダーに保存されるサブディレクトリ。", "kerberosvault_description_directory": "録音がプロバイダーに保存されるサブディレクトリ。",
"kerberosvault_accesskey": "アクセスキー", "kerberosvault_accesskey": "アクセスキー",
"kerberosvault_description_accesskey": "Kerberos Vault アカウントのアクセス キー。", "kerberosvault_description_accesskey": "Kerberos Vault アカウントのアクセス キー。",

View File

@@ -4,7 +4,8 @@
"configure": "Instellingen" "configure": "Instellingen"
}, },
"buttons": { "buttons": {
"save": "Opslaan" "save": "Opslaan",
"verify_connection": "Verifieer Connectie"
}, },
"navigation": { "navigation": {
"profile": "Profiel", "profile": "Profiel",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Er ging iets fout tijdens het controleren van de opslag instellingen", "verify_persistence_error": "Er ging iets fout tijdens het controleren van de opslag instellingen",
"verify_camera": "We controleren de camera instellingen.", "verify_camera": "We controleren de camera instellingen.",
"verify_camera_success": "De camera instellingen zijn gevalideerd.", "verify_camera_success": "De camera instellingen zijn gevalideerd.",
"verify_camera_error": "Er ging iets mis met de camera instellingen." "verify_camera_error": "Er ging iets mis met de camera instellingen.",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "Algemeen", "general": "Algemeen",
@@ -187,13 +191,13 @@
"kerberoshub_description_region": "De regio waar jouw opnames worden opgeslagen.", "kerberoshub_description_region": "De regio waar jouw opnames worden opgeslagen.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "De bucket opslag locatie", "kerberoshub_description_bucket": "De bucket opslag locatie",
"kerberoshub_username": "Gebruikersnaam/Map", "kerberoshub_username": "Gebruikersnaam/Map (moet overeenkomen met de Kerberos Hub username)",
"kerberoshub_description_username": "De gebruikersnaam van jouw Kerberos Hub account.", "kerberoshub_description_username": "De gebruikersnaam van jouw Kerberos Hub account.",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "De Kerberos Vault API", "kerberosvault_description_apiurl": "De Kerberos Vault API",
"kerberosvault_provider": "Provider", "kerberosvault_provider": "Provider",
"kerberosvault_description_provider": "De provider verantwoordelijk voor de opnames op te slaan.", "kerberosvault_description_provider": "De provider verantwoordelijk voor de opnames op te slaan.",
"kerberosvault_directory": "Map", "kerberosvault_directory": "Map (moet overeenkomen met de Kerberos Hub username)",
"kerberosvault_description_directory": "Sub map waarin de opnames worden opgeslagen.", "kerberosvault_description_directory": "Sub map waarin de opnames worden opgeslagen.",
"kerberosvault_accesskey": "Access key", "kerberosvault_accesskey": "Access key",
"kerberosvault_description_accesskey": "De access key van jouw Kerberos Vault account.", "kerberosvault_description_accesskey": "De access key van jouw Kerberos Vault account.",

View File

@@ -4,7 +4,8 @@
"configure": "Configure" "configure": "Configure"
}, },
"buttons": { "buttons": {
"save": "Save" "save": "Save",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "Profil", "profile": "Profil",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Something went wrong while verifying the persistence", "verify_persistence_error": "Something went wrong while verifying the persistence",
"verify_camera": "Verifying your camera settings.", "verify_camera": "Verifying your camera settings.",
"verify_camera_success": "Camera settings are successfully verified.", "verify_camera_success": "Camera settings are successfully verified.",
"verify_camera_error": "Something went wrong while verifying the camera settings" "verify_camera_error": "Something went wrong while verifying the camera settings",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "General", "general": "General",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "The region we are storing our recordings in.", "kerberoshub_description_region": "The region we are storing our recordings in.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "The bucket we are storing our recordings in.", "kerberoshub_description_bucket": "The bucket we are storing our recordings in.",
"kerberoshub_username": "Username/Directory", "kerberoshub_username": "Username/Directory (should match Kerberos Hub username)",
"kerberoshub_description_username": "The username of your Kerberos Hub account.", "kerberoshub_description_username": "The username of your Kerberos Hub account.",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "The Kerberos Vault API", "kerberosvault_description_apiurl": "The Kerberos Vault API",
"kerberosvault_provider": "Provider", "kerberosvault_provider": "Provider",
"kerberosvault_description_provider": "The provider to which your recordings will be send.", "kerberosvault_description_provider": "The provider to which your recordings will be send.",
"kerberosvault_directory": "Directory", "kerberosvault_directory": "Directory (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.", "kerberosvault_description_directory": "Sub directory the recordings will be stored in your provider.",
"kerberosvault_accesskey": "Access key", "kerberosvault_accesskey": "Access key",
"kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.", "kerberosvault_description_accesskey": "The access key of your Kerberos Vault account.",

View File

@@ -4,7 +4,8 @@
"configure": "Configurar" "configure": "Configurar"
}, },
"buttons": { "buttons": {
"save": "Salvar" "save": "Salvar",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "Perfil", "profile": "Perfil",
@@ -69,7 +70,10 @@
"verify_persistence_error": "Algo deu errado ao verificar o armazenamento", "verify_persistence_error": "Algo deu errado ao verificar o armazenamento",
"verify_camera": "Verificando as configurações de sua câmera.", "verify_camera": "Verificando as configurações de sua câmera.",
"verify_camera_success": "As configurações da câmera foram verificadas com sucesso.", "verify_camera_success": "As configurações da câmera foram verificadas com sucesso.",
"verify_camera_error": "Algo deu errado ao verificar as configurações da câmera." "verify_camera_error": "Algo deu errado ao verificar as configurações da câmera.",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "Geral", "general": "Geral",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "A região em que estamos armazenando nossas gravações.", "kerberoshub_description_region": "A região em que estamos armazenando nossas gravações.",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "O bucket no qual estamos armazenando nossas gravações.", "kerberoshub_description_bucket": "O bucket no qual estamos armazenando nossas gravações.",
"kerberoshub_username": "Nome de usuário/diretório (Username/Directory)", "kerberoshub_username": "Nome de usuário/diretório (should match Kerberos Hub username)",
"kerberoshub_description_username": "O nome de usuário da sua conta do Kerberos Hub.", "kerberoshub_description_username": "O nome de usuário da sua conta do Kerberos Hub.",
"kerberosvault_apiurl": "Url da API do Kerberos Vault", "kerberosvault_apiurl": "Url da API do Kerberos Vault",
"kerberosvault_description_apiurl": "a API Kerberos Vault", "kerberosvault_description_apiurl": "a API Kerberos Vault",
"kerberosvault_provider": "Provedor", "kerberosvault_provider": "Provedor",
"kerberosvault_description_provider": "O provedor para o qual suas gravações serão enviadas.", "kerberosvault_description_provider": "O provedor para o qual suas gravações serão enviadas.",
"kerberosvault_directory": "Diretório", "kerberosvault_directory": "Diretório (should match Kerberos Hub username)",
"kerberosvault_description_directory": "Subdiretório as gravações serão armazenadas em seu provedor.", "kerberosvault_description_directory": "Subdiretório as gravações serão armazenadas em seu provedor.",
"kerberosvault_accesskey": "Chave de acesso(Access key)", "kerberosvault_accesskey": "Chave de acesso(Access key)",
"kerberosvault_description_accesskey": "A chave de acesso da sua conta do Kerberos Vault.", "kerberosvault_description_accesskey": "A chave de acesso da sua conta do Kerberos Vault.",

View File

@@ -4,7 +4,8 @@
"configure": "配置" "configure": "配置"
}, },
"buttons": { "buttons": {
"save": "保存" "save": "保存",
"verify_connection": "Verify Connection"
}, },
"navigation": { "navigation": {
"profile": "配置文件", "profile": "配置文件",
@@ -69,7 +70,10 @@
"verify_persistence_error": "验证持久化存储时出错", "verify_persistence_error": "验证持久化存储时出错",
"verify_camera": "验证您的相机设置", "verify_camera": "验证您的相机设置",
"verify_camera_success": "相机设置验证成功", "verify_camera_success": "相机设置验证成功",
"verify_camera_error": "验证相机设置时出错" "verify_camera_error": "验证相机设置时出错",
"verify_onvif": "Verifying your ONVIF settings.",
"verify_onvif_success": "ONVIF settings are successfully verified.",
"verify_onvif_error": "Something went wrong while verifying the ONVIF settings"
}, },
"overview": { "overview": {
"general": "常规", "general": "常规",
@@ -186,13 +190,13 @@
"kerberoshub_description_region": "存储录像的区域", "kerberoshub_description_region": "存储录像的区域",
"kerberoshub_bucket": "Bucket", "kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "存储录像的桶", "kerberoshub_description_bucket": "存储录像的桶",
"kerberoshub_username": "账户/目录", "kerberoshub_username": "账户/目录 (should match Kerberos Hub username)",
"kerberoshub_description_username": "您的 Kerberos Hub 帐户的用户名", "kerberoshub_description_username": "您的 Kerberos Hub 帐户的用户名",
"kerberosvault_apiurl": "Kerberos Vault API URL", "kerberosvault_apiurl": "Kerberos Vault API URL",
"kerberosvault_description_apiurl": "Kerberos Vault API", "kerberosvault_description_apiurl": "Kerberos Vault API",
"kerberosvault_provider": "供应商", "kerberosvault_provider": "供应商",
"kerberosvault_description_provider": "您的录像将会被发送到的提供商", "kerberosvault_description_provider": "您的录像将会被发送到的提供商",
"kerberosvault_directory": "目录", "kerberosvault_directory": "目录 (should match Kerberos Hub username)",
"kerberosvault_description_directory": "录像将存储在提供商中的子目录", "kerberosvault_description_directory": "录像将存储在提供商中的子目录",
"kerberosvault_accesskey": "访问密钥", "kerberosvault_accesskey": "访问密钥",
"kerberosvault_description_accesskey": "Kerberos Vault 帐户的访问密钥", "kerberosvault_description_accesskey": "Kerberos Vault 帐户的访问密钥",

View File

@@ -38,6 +38,16 @@ class App extends React.Component {
dispatchGetDashboardInformation(); dispatchGetDashboardInformation();
dispatchConnect(); dispatchConnect();
const connectInterval = interval(1000);
this.connectionSubscription = connectInterval.subscribe(() => {
const { connected } = this.props;
if (connected) {
// Already connected
} else {
dispatchConnect();
}
});
const interval$ = interval(5000); const interval$ = interval(5000);
this.subscription = interval$.subscribe(() => { this.subscription = interval$.subscribe(() => {
dispatchGetDashboardInformation(); dispatchGetDashboardInformation();
@@ -64,6 +74,7 @@ class App extends React.Component {
componentWillUnmount() { componentWillUnmount() {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
this.connectionSubscription.unsubscribe();
const message = { const message = {
client_id: uuid(), client_id: uuid(),
message_type: 'goodbye', message_type: 'goodbye',

View File

@@ -1,6 +1,7 @@
import { import {
doGetConfig, doGetConfig,
doSaveConfig, doSaveConfig,
doVerifyOnvif,
doVerifyHub, doVerifyHub,
doVerifyPersistence, doVerifyPersistence,
doGetKerberosAgentTags, doGetKerberosAgentTags,
@@ -39,6 +40,28 @@ export const updateRegion = (id, polygon) => {
}; };
}; };
export const verifyOnvif = (config, onSuccess, onError) => {
return (dispatch) => {
doVerifyOnvif(
config,
(data) => {
dispatch({
type: 'VERIFY_ONVIF',
});
if (onSuccess) {
onSuccess(data);
}
},
(error) => {
const { message } = error;
if (onError) {
onError(message);
}
}
);
};
};
export const verifyCamera = (streamType, config, onSuccess, onError) => { export const verifyCamera = (streamType, config, onSuccess, onError) => {
return (dispatch) => { return (dispatch) => {
doVerifyCamera( doVerifyCamera(

View File

@@ -91,6 +91,26 @@ export function doVerifyHub(config, onSuccess, onError) {
}); });
} }
export function doVerifyOnvif(config, onSuccess, onError) {
const endpoint = API.post(`onvif/verify`, {
...config,
});
endpoint
.then((res) => {
if (res.status !== 200) {
throw new Error(res.data);
}
return res.data;
})
.then((data) => {
onSuccess(data);
})
.catch((e) => {
const { data } = e.response;
onError(data);
});
}
export function doVerifyCamera(streamType, config, onSuccess, onError) { export function doVerifyCamera(streamType, config, onSuccess, onError) {
const cameraStreams = { const cameraStreams = {
rtsp: '', rtsp: '',

View File

@@ -50,7 +50,9 @@ function getAuthState() {
} }
} }
const reduxWebsocketMiddleware = reduxWebsocket(); const reduxWebsocketMiddleware = reduxWebsocket({
reconnectOnClose: true,
});
const store = createStore( const store = createStore(
rootReducer(history), rootReducer(history),

View File

@@ -4,6 +4,7 @@ import { Link, withRouter } from 'react-router-dom';
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import { send } from '@giantmachines/redux-websocket'; import { send } from '@giantmachines/redux-websocket';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { interval } from 'rxjs';
import { import {
Breadcrumb, Breadcrumb,
KPI, KPI,
@@ -66,6 +67,11 @@ class Dashboard extends React.Component {
message_type: 'stream-sd', message_type: 'stream-sd',
}; };
dispatchSend(message); dispatchSend(message);
const requestStreamInterval = interval(3000);
this.requestStreamSubscription = requestStreamInterval.subscribe(() => {
dispatchSend(message);
});
} }
} }
@@ -75,6 +81,9 @@ class Dashboard extends React.Component {
liveview[0].remove(); liveview[0].remove();
} }
if (this.requestStreamSubscription) {
this.requestStreamSubscription.unsubscribe();
}
const { dispatchSend } = this.props; const { dispatchSend } = this.props;
const message = { const message = {
message_type: 'stop-sd', message_type: 'stop-sd',

View File

@@ -27,6 +27,7 @@ import {
updateRegion, updateRegion,
removeRegion, removeRegion,
saveConfig, saveConfig,
verifyOnvif,
verifyCamera, verifyCamera,
verifyHub, verifyHub,
verifyPersistence, verifyPersistence,
@@ -63,6 +64,9 @@ class Settings extends React.Component {
verifyCameraSuccess: false, verifyCameraSuccess: false,
verifyCameraError: false, verifyCameraError: false,
verifyCameraMessage: '', verifyCameraMessage: '',
verifyOnvifSuccess: false,
verifyOnvifError: false,
verifyOnvifErrorMessage: '',
loading: false, loading: false,
loadingHub: false, loadingHub: false,
loadingCamera: false, loadingCamera: false,
@@ -127,6 +131,7 @@ class Settings extends React.Component {
this.onAddRegion = this.onAddRegion.bind(this); this.onAddRegion = this.onAddRegion.bind(this);
this.onUpdateRegion = this.onUpdateRegion.bind(this); this.onUpdateRegion = this.onUpdateRegion.bind(this);
this.onDeleteRegion = this.onDeleteRegion.bind(this); this.onDeleteRegion = this.onDeleteRegion.bind(this);
this.verifyONVIF = this.verifyONVIF.bind(this);
} }
componentDidMount() { componentDidMount() {
@@ -274,6 +279,8 @@ class Settings extends React.Component {
verifyHubError: false, verifyHubError: false,
configSuccess: false, configSuccess: false,
configError: false, configError: false,
verifyOnvifSuccess: false,
verifyOnvifError: false,
}); });
if (config) { if (config) {
@@ -295,6 +302,53 @@ class Settings extends React.Component {
} }
} }
verifyONVIF() {
const { config, dispatchVerifyOnvif } = this.props;
// Get camera configuration (subset of config).
const cameraConfig = {
onvif_xaddr: config.config.capture.ipcamera.onvif_xaddr,
onvif_username: config.config.capture.ipcamera.onvif_username,
onvif_password: config.config.capture.ipcamera.onvif_password,
};
this.setState({
verifyOnvifSuccess: false,
verifyOnvifError: false,
verifyOnvifErrorMessage: '',
verifyCameraSuccess: false,
verifyCameraError: false,
verifyCameraErrorMessage: '',
configSuccess: false,
configError: false,
loadingCamera: false,
loadingOnvif: true,
});
if (config) {
dispatchVerifyOnvif(
cameraConfig,
(data) => {
console.log(data);
this.setState({
verifyOnvifSuccess: true,
verifyOnvifError: false,
verifyOnvifErrorMessage: '',
loadingOnvif: false,
});
},
(error) => {
this.setState({
verifyOnvifSuccess: false,
verifyOnvifError: true,
verifyOnvifErrorMessage: error,
loadingOnvif: false,
});
}
);
}
}
verifyHubSettings() { verifyHubSettings() {
const { config, dispatchVerifyHub } = this.props; const { config, dispatchVerifyHub } = this.props;
if (config) { if (config) {
@@ -317,6 +371,8 @@ class Settings extends React.Component {
verifyCameraSuccess: false, verifyCameraSuccess: false,
verifyCameraError: false, verifyCameraError: false,
verifyCameraErrorMessage: '', verifyCameraErrorMessage: '',
verifyOnvifSuccess: false,
verifyOnvifError: false,
loadingHub: true, loadingHub: true,
}); });
@@ -362,6 +418,8 @@ class Settings extends React.Component {
persistenceError: false, persistenceError: false,
verifyCameraSuccess: false, verifyCameraSuccess: false,
verifyCameraError: false, verifyCameraError: false,
verifyOnvifSuccess: false,
verifyOnvifError: false,
verifyCameraErrorMessage: '', verifyCameraErrorMessage: '',
loading: true, loading: true,
}); });
@@ -402,6 +460,7 @@ class Settings extends React.Component {
this.setState({ this.setState({
configSuccess: false, configSuccess: false,
configError: false, configError: false,
loadingCamera: true,
verifyPersistenceSuccess: false, verifyPersistenceSuccess: false,
verifyPersistenceError: false, verifyPersistenceError: false,
verifyHubSuccess: false, verifyHubSuccess: false,
@@ -410,9 +469,10 @@ class Settings extends React.Component {
verifyCameraSuccess: false, verifyCameraSuccess: false,
verifyCameraError: false, verifyCameraError: false,
verifyCameraErrorMessage: '', verifyCameraErrorMessage: '',
verifyOnvifSuccess: false,
verifyOnvifError: false,
hubSuccess: false, hubSuccess: false,
hubError: false, hubError: false,
loadingCamera: true,
}); });
dispatchVerifyCamera( dispatchVerifyCamera(
@@ -453,6 +513,10 @@ class Settings extends React.Component {
verifyCameraSuccess, verifyCameraSuccess,
verifyCameraError, verifyCameraError,
verifyCameraErrorMessage, verifyCameraErrorMessage,
loadingOnvif,
verifyOnvifSuccess,
verifyOnvifError,
verifyOnvifErrorMessage,
loadingCamera, loadingCamera,
loading, loading,
loadingHub, loadingHub,
@@ -652,10 +716,23 @@ class Settings extends React.Component {
type="alert" type="alert"
message={`${t( message={`${t(
'settings.info.verify_camera_error' 'settings.info.verify_camera_error'
)} :${verifyCameraErrorMessage}`} )}: ${verifyCameraErrorMessage}`}
/> />
)} )}
{loadingOnvif && (
<InfoBar type="loading" message={t('settings.info.verify_onvif')} />
)}
{verifyOnvifSuccess && (
<InfoBar
type="success"
message={t('settings.info.verify_onvif_success')}
/>
)}
{verifyOnvifError && (
<InfoBar type="alert" message={`${verifyOnvifErrorMessage}`} />
)}
{loadingHub && ( {loadingHub && (
<InfoBar type="loading" message={t('settings.info.verify_hub')} /> <InfoBar type="loading" message={t('settings.info.verify_hub')} />
)} )}
@@ -1103,7 +1180,7 @@ class Settings extends React.Component {
noPadding noPadding
label={t('settings.camera.onvif_xaddr')} label={t('settings.camera.onvif_xaddr')}
value={config.capture.ipcamera.onvif_xaddr} value={config.capture.ipcamera.onvif_xaddr}
placeholder="http://x.x.x.x/onvif/device_service" placeholder="x.x.x.x:yyyy"
onChange={(value) => onChange={(value) =>
this.onUpdateField( this.onUpdateField(
'capture.ipcamera', 'capture.ipcamera',
@@ -1143,6 +1220,12 @@ class Settings extends React.Component {
/> />
</BlockBody> </BlockBody>
<BlockFooter> <BlockFooter>
<Button
label={t('buttons.verify_connection')}
type="default"
icon="verify"
onClick={this.verifyONVIF}
/>
<Button <Button
label={t('buttons.save')} label={t('buttons.save')}
type="default" type="default"
@@ -2245,6 +2328,8 @@ const mapStateToProps = (state /* , ownProps */) => ({
}); });
const mapDispatchToProps = (dispatch /* , ownProps */) => ({ const mapDispatchToProps = (dispatch /* , ownProps */) => ({
dispatchVerifyOnvif: (config, success, error) =>
dispatch(verifyOnvif(config, success, error)),
dispatchVerifyCamera: (streamType, config, success, error) => dispatchVerifyCamera: (streamType, config, success, error) =>
dispatch(verifyCamera(streamType, config, success, error)), dispatch(verifyCamera(streamType, config, success, error)),
dispatchVerifyHub: (config, success, error) => dispatchVerifyHub: (config, success, error) =>
@@ -2272,6 +2357,7 @@ Settings.propTypes = {
dispatchUpdateRegion: PropTypes.func.isRequired, dispatchUpdateRegion: PropTypes.func.isRequired,
dispatchRemoveRegion: PropTypes.func.isRequired, dispatchRemoveRegion: PropTypes.func.isRequired,
dispatchVerifyCamera: PropTypes.func.isRequired, dispatchVerifyCamera: PropTypes.func.isRequired,
dispatchVerifyOnvif: PropTypes.func.isRequired,
}; };
export default withTranslation()( export default withTranslation()(