mirror of
https://github.com/kerberos-io/agent.git
synced 2026-03-03 13:50:11 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baca44beef | ||
|
|
d7580744e2 | ||
|
|
04f4bc9bf2 | ||
|
|
d879174f4c | ||
|
|
5a1a62a723 | ||
|
|
c519b01092 | ||
|
|
c2ff7ff785 | ||
|
|
44ec8c0534 | ||
|
|
21c0e01137 | ||
|
|
f7ced6056d | ||
|
|
00917e3f88 |
12
.github/workflows/docker.yml
vendored
12
.github/workflows/docker.yml
vendored
@@ -43,6 +43,7 @@ jobs:
|
||||
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-$(echo ${{matrix.architecture}} | tr / -)-${{steps.short-sha.outputs.sha}} --output type=tar,dest=output-${{matrix.architecture}}.tar .
|
||||
- name: Strip binary
|
||||
run: mkdir -p output/ && tar -xf output-${{matrix.architecture}}.tar -C output && rm output-${{matrix.architecture}}.tar && cd output/ && tar -cf ../agent-${{matrix.architecture}}.tar -C home/agent . && rm -rf output
|
||||
# We'll make a GitHub release and push the build (tar) as an artifact
|
||||
- uses: rickstaa/action-create-tag@v1
|
||||
with:
|
||||
tag: ${{ steps.short-sha.outputs.sha }}
|
||||
@@ -54,6 +55,17 @@ jobs:
|
||||
name: ${{ steps.short-sha.outputs.sha }}
|
||||
tag: ${{ steps.short-sha.outputs.sha }}
|
||||
artifacts: "agent-${{matrix.architecture}}.tar"
|
||||
# Taken from GoReleaser's own release workflow.
|
||||
# The available Snapcraft Action has some bugs described in the issue below.
|
||||
# The mkdirs are a hack for https://github.com/goreleaser/goreleaser/issues/1715.
|
||||
- name: Setup Snapcraft
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft
|
||||
mkdir -p $HOME/.cache/snapcraft/download
|
||||
mkdir -p $HOME/.cache/snapcraft/stage-packages
|
||||
- name: Use Snapcraft
|
||||
run: tar -xf agent-${{matrix.architecture}}.tar && snapcraft
|
||||
build-other:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
|
||||
@@ -10,7 +10,7 @@ ENV GOSUMDB=off
|
||||
##########################################
|
||||
# Installing some additional dependencies.
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
RUN apt-get upgrade -y && apt-get update && apt-get install -y --no-install-recommends \
|
||||
git build-essential cmake pkg-config unzip libgtk2.0-dev \
|
||||
curl ca-certificates libcurl4-openssl-dev libssl-dev libjpeg62-turbo-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -147,4 +147,4 @@ HEALTHCHECK CMD curl --fail http://localhost:80 || exit 1
|
||||
# Leeeeettttt'ssss goooooo!!!
|
||||
# Run the shizzle from the right working directory.
|
||||
WORKDIR /home/agent
|
||||
CMD ["./main", "run", "opensource", "80"]
|
||||
CMD ["./main", "-action", "run", "-port", "80"]
|
||||
|
||||
15
README.md
15
README.md
@@ -183,8 +183,11 @@ Next to attaching the configuration file, it is also possible to override the co
|
||||
| `AGENT_CAPTURE_IPCAMERA_ONVIF_XADDR` | ONVIF endpoint/address running on the camera. | "" |
|
||||
| `AGENT_CAPTURE_IPCAMERA_ONVIF_USERNAME` | ONVIF username to authenticate against. | "" |
|
||||
| `AGENT_CAPTURE_IPCAMERA_ONVIF_PASSWORD` | ONVIF password to authenticate against. | "" |
|
||||
| `AGENT_CAPTURE_MOTION` | Toggle for enabling or disabling motion. | "true" |
|
||||
| `AGENT_CAPTURE_LIVEVIEW` | Toggle for enabling or disabling liveview. | "true" |
|
||||
| `AGENT_CAPTURE_SNAPSHOTS` | Toggle for enabling or disabling snapshot generation. | "true" |
|
||||
| `AGENT_CAPTURE_RECORDING` | Toggle for enabling making recordings. | "true" |
|
||||
| `AGENT_CAPTURE_CONTINUOUS` | Toggle for enabling continuous or motion based recording. | "false" |
|
||||
| `AGENT_CAPTURE_CONTINUOUS` | Toggle for enabling continuous "true" or motion "false". | "false" |
|
||||
| `AGENT_CAPTURE_PRERECORDING` | If `CONTINUOUS` set to `false`, specify the recording time (seconds) before after motion event. | "10" |
|
||||
| `AGENT_CAPTURE_POSTRECORDING` | If `CONTINUOUS` set to `false`, specify the recording time (seconds) after motion event. | "20" |
|
||||
| `AGENT_CAPTURE_MAXLENGTH` | The maximum length of a single recording (seconds). | "30" |
|
||||
@@ -233,9 +236,9 @@ On opening of the GitHub Codespace, some dependencies will be installed. Once th
|
||||
const dev = {
|
||||
ENV: 'dev',
|
||||
HOSTNAME: externalHost,
|
||||
//API_URL: `${protocol}//${hostname}:8080/api`,
|
||||
//URL: `${protocol}//${hostname}:8080`,
|
||||
//WS_URL: `${websocketprotocol}//${hostname}:8080/ws`,
|
||||
//API_URL: `${protocol}//${hostname}:80/api`,
|
||||
//URL: `${protocol}//${hostname}:80`,
|
||||
//WS_URL: `${websocketprotocol}//${hostname}:80/ws`,
|
||||
|
||||
// Uncomment, and comment the above lines, when using codespaces or other special DNS names (which you can't control)
|
||||
API_URL: `${protocol}//${externalHost}/api`,
|
||||
@@ -248,7 +251,7 @@ Go and open two terminals one for the `ui` project and one for the `machinery` p
|
||||
1. Terminal A:
|
||||
|
||||
cd machinery/
|
||||
go run main.go run camera 80
|
||||
go run main.go -action run -port 80
|
||||
|
||||
2. Terminal B:
|
||||
|
||||
@@ -289,7 +292,7 @@ You can simply run the `machinery` using following commands.
|
||||
|
||||
git clone https://github.com/kerberos-io/agent
|
||||
cd machinery
|
||||
go run main.go run mycameraname 80
|
||||
go run main.go -action run -port 80
|
||||
|
||||
This will launch the Kerberos Agent and run a webserver on port `80`. You can change the port by your own preference. We strongly support the usage of [Goland](https://www.jetbrains.com/go/) or [Visual Studio Code](https://code.visualstudio.com/), as it comes with all the debugging and linting features builtin.
|
||||
|
||||
|
||||
2
machinery/.vscode/launch.json
vendored
2
machinery/.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "main.go",
|
||||
"args": ["run", "cameraname", "8080"],
|
||||
"args": ["-action run"],
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"buildFlags": "--tags dynamic",
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -49,10 +50,23 @@ func main() {
|
||||
}
|
||||
|
||||
// Start the show ;)
|
||||
action := os.Args[1]
|
||||
// We'll parse the flags (named variables), and start the agent.
|
||||
|
||||
var action string
|
||||
var configDirectory string
|
||||
var name string
|
||||
var port string
|
||||
var timeout string
|
||||
|
||||
flag.StringVar(&action, "action", "version", "Tell us what you want do 'run' or 'version'")
|
||||
flag.StringVar(&configDirectory, "config", ".", "Where is the configuration stored")
|
||||
flag.StringVar(&name, "name", "agent", "Provide a name for the agent")
|
||||
flag.StringVar(&port, "port", "80", "On which port should the agent run")
|
||||
flag.StringVar(&timeout, "timeout", "2000", "Number of milliseconds to wait for the ONVIF discovery to complete")
|
||||
flag.Parse()
|
||||
|
||||
timezone, _ := time.LoadLocation("CET")
|
||||
log.Log.Init(timezone)
|
||||
log.Log.Init(configDirectory, timezone)
|
||||
|
||||
switch action {
|
||||
|
||||
@@ -60,14 +74,10 @@ func main() {
|
||||
log.Log.Info("You are currrently running Kerberos Agent " + VERSION)
|
||||
|
||||
case "discover":
|
||||
timeout := os.Args[2]
|
||||
log.Log.Info(timeout)
|
||||
|
||||
case "run":
|
||||
{
|
||||
name := os.Args[2]
|
||||
port := os.Args[3]
|
||||
|
||||
// Print Kerberos.io ASCII art
|
||||
utils.PrintASCIIArt()
|
||||
|
||||
@@ -82,7 +92,7 @@ func main() {
|
||||
configuration.Port = port
|
||||
|
||||
// Open this configuration either from Kerberos Agent or Kerberos Factory.
|
||||
components.OpenConfig(&configuration)
|
||||
components.OpenConfig(configDirectory, &configuration)
|
||||
|
||||
// We will override the configuration with the environment variables
|
||||
components.OverrideWithEnvironmentVariables(&configuration)
|
||||
@@ -92,18 +102,18 @@ func main() {
|
||||
|
||||
// Check the folder permissions, it might be that we do not have permissions to write
|
||||
// recordings, update the configuration or save snapshots.
|
||||
utils.CheckDataDirectoryPermissions()
|
||||
utils.CheckDataDirectoryPermissions(configDirectory)
|
||||
|
||||
// Set timezone
|
||||
timezone, _ := time.LoadLocation(configuration.Config.Timezone)
|
||||
log.Log.Init(timezone)
|
||||
log.Log.Init(configDirectory, timezone)
|
||||
|
||||
// Check if we have a device Key or not, if not
|
||||
// we will generate one.
|
||||
if configuration.Config.Key == "" {
|
||||
key := utils.RandStringBytesMaskImpr(30)
|
||||
configuration.Config.Key = key
|
||||
err := components.StoreConfig(configuration.Config)
|
||||
err := components.StoreConfig(configDirectory, configuration.Config)
|
||||
if err == nil {
|
||||
log.Log.Info("Main: updated unique key for agent to: " + key)
|
||||
} else {
|
||||
@@ -121,10 +131,10 @@ func main() {
|
||||
CancelContext: &cancel,
|
||||
HandleBootstrap: make(chan string, 1),
|
||||
}
|
||||
go components.Bootstrap(&configuration, &communication)
|
||||
go components.Bootstrap(configDirectory, &configuration, &communication)
|
||||
|
||||
// Start the REST API.
|
||||
routers.StartWebserver(&configuration, &communication)
|
||||
routers.StartWebserver(configDirectory, &configuration, &communication)
|
||||
}
|
||||
default:
|
||||
log.Log.Error("Main: Sorry I don't understand :(")
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/kerberos-io/joy4/av"
|
||||
)
|
||||
|
||||
func CleanupRecordingDirectory(configuration *models.Configuration) {
|
||||
func CleanupRecordingDirectory(configDirectory string, configuration *models.Configuration) {
|
||||
autoClean := configuration.Config.AutoClean
|
||||
if autoClean == "true" {
|
||||
maxSize := configuration.Config.MaxDirectorySize
|
||||
@@ -25,7 +25,7 @@ func CleanupRecordingDirectory(configuration *models.Configuration) {
|
||||
maxSize = 300
|
||||
}
|
||||
// Total size of the recording directory.
|
||||
recordingsDirectory := "./data/recordings"
|
||||
recordingsDirectory := configDirectory + "/data/recordings"
|
||||
size, err := utils.DirSize(recordingsDirectory)
|
||||
if err == nil {
|
||||
sizeInMB := size / 1000 / 1000
|
||||
@@ -51,7 +51,7 @@ func CleanupRecordingDirectory(configuration *models.Configuration) {
|
||||
}
|
||||
}
|
||||
|
||||
func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration, communication *models.Communication, streams []av.CodecData) {
|
||||
func HandleRecordStream(queue *pubsub.Queue, configDirectory string, configuration *models.Configuration, communication *models.Communication, streams []av.CodecData) {
|
||||
|
||||
config := configuration.Config
|
||||
|
||||
@@ -134,13 +134,13 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
|
||||
}
|
||||
|
||||
// Create a symbol link.
|
||||
fc, _ := os.Create("./data/cloud/" + name)
|
||||
fc, _ := os.Create(configDirectory + "/data/cloud/" + name)
|
||||
fc.Close()
|
||||
|
||||
recordingStatus = "idle"
|
||||
|
||||
// Clean up the recording directory if necessary.
|
||||
CleanupRecordingDirectory(configuration)
|
||||
CleanupRecordingDirectory(configDirectory, configuration)
|
||||
}
|
||||
|
||||
// If not yet started and a keyframe, let's make a recording
|
||||
@@ -192,7 +192,7 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
|
||||
"769"
|
||||
|
||||
name = s + ".mp4"
|
||||
fullName = "./data/recordings/" + name
|
||||
fullName = configDirectory + "/data/recordings/" + name
|
||||
|
||||
// Running...
|
||||
log.Log.Info("Recording started")
|
||||
@@ -259,7 +259,7 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
|
||||
}
|
||||
|
||||
// Create a symbol link.
|
||||
fc, _ := os.Create("./data/cloud/" + name)
|
||||
fc, _ := os.Create(configDirectory + "/data/cloud/" + name)
|
||||
fc.Close()
|
||||
|
||||
recordingStatus = "idle"
|
||||
@@ -315,7 +315,7 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
|
||||
"769"
|
||||
|
||||
name := s + ".mp4"
|
||||
fullName := "./data/recordings/" + name
|
||||
fullName := configDirectory + "/data/recordings/" + name
|
||||
|
||||
// Running...
|
||||
log.Log.Info("HandleRecordStream: Recording started")
|
||||
@@ -406,11 +406,11 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
|
||||
}
|
||||
|
||||
// Create a symbol linc.
|
||||
fc, _ := os.Create("./data/cloud/" + name)
|
||||
fc, _ := os.Create(configDirectory + "/data/cloud/" + name)
|
||||
fc.Close()
|
||||
|
||||
// Clean up the recording directory if necessary.
|
||||
CleanupRecordingDirectory(configuration)
|
||||
CleanupRecordingDirectory(configDirectory, configuration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import (
|
||||
"github.com/kerberos-io/agent/machinery/src/webrtc"
|
||||
)
|
||||
|
||||
func PendingUpload() {
|
||||
ff, err := utils.ReadDirectory("./data/cloud/")
|
||||
func PendingUpload(configDirectory string) {
|
||||
ff, err := utils.ReadDirectory(configDirectory + "/data/cloud/")
|
||||
if err == nil {
|
||||
for _, f := range ff {
|
||||
log.Log.Info(f.Name())
|
||||
@@ -41,12 +41,12 @@ func PendingUpload() {
|
||||
}
|
||||
}
|
||||
|
||||
func HandleUpload(configuration *models.Configuration, communication *models.Communication) {
|
||||
func HandleUpload(configDirectory string, configuration *models.Configuration, communication *models.Communication) {
|
||||
|
||||
log.Log.Debug("HandleUpload: started")
|
||||
|
||||
config := configuration.Config
|
||||
watchDirectory := "./data/cloud/"
|
||||
watchDirectory := configDirectory + "/data/cloud/"
|
||||
|
||||
if config.Offline == "true" {
|
||||
log.Log.Debug("HandleUpload: stopping as Offline is enabled.")
|
||||
@@ -122,7 +122,7 @@ func HandleUpload(configuration *models.Configuration, communication *models.Com
|
||||
// Check if we need to remove the original recording
|
||||
// removeAfterUpload is set to false by default
|
||||
if config.RemoveAfterUpload == "true" {
|
||||
err := os.Remove("./data/recordings/" + fileName)
|
||||
err := os.Remove(configDirectory + "/data/recordings/" + fileName)
|
||||
if err != nil {
|
||||
log.Log.Error("HandleUpload: " + err.Error())
|
||||
}
|
||||
@@ -614,7 +614,7 @@ func VerifyHub(c *gin.Context) {
|
||||
// @Summary Will verify the persistence.
|
||||
// @Description Will verify the persistence.
|
||||
// @Success 200 {object} models.APIResponse
|
||||
func VerifyPersistence(c *gin.Context) {
|
||||
func VerifyPersistence(c *gin.Context, configDirectory string) {
|
||||
|
||||
var config models.Config
|
||||
err := c.BindJSON(&config)
|
||||
@@ -636,7 +636,7 @@ func VerifyPersistence(c *gin.Context) {
|
||||
} else {
|
||||
|
||||
// Open test-480p.mp4
|
||||
file, err := os.Open("./data/test-480p.mp4")
|
||||
file, err := os.Open(configDirectory + "/data/test-480p.mp4")
|
||||
if err != nil {
|
||||
msg := "VerifyPersistence: error reading test-480p.mp4: " + err.Error()
|
||||
log.Log.Error(msg)
|
||||
@@ -741,7 +741,7 @@ func VerifyPersistence(c *gin.Context) {
|
||||
"_6-967003_" + config.Name + "_200-200-400-400_24_769.mp4"
|
||||
|
||||
// Open test-480p.mp4
|
||||
file, err := os.Open("./data/test-480p.mp4")
|
||||
file, err := os.Open(configDirectory + "/test-480p.mp4")
|
||||
if err != nil {
|
||||
msg := "VerifyPersistence: error reading test-480p.mp4: " + err.Error()
|
||||
log.Log.Error(msg)
|
||||
|
||||
@@ -20,14 +20,14 @@ import (
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetImageFromFilePath() (image.Image, error) {
|
||||
snapshotDirectory := "./data/snapshots"
|
||||
func GetImageFromFilePath(configDirectory string) (image.Image, error) {
|
||||
snapshotDirectory := configDirectory + "/data/snapshots"
|
||||
files, err := ioutil.ReadDir(snapshotDirectory)
|
||||
if err == nil && len(files) > 1 {
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].ModTime().Before(files[j].ModTime())
|
||||
})
|
||||
filePath := "./data/snapshots/" + files[1].Name()
|
||||
filePath := configDirectory + "/data/snapshots/" + files[1].Name()
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -42,11 +42,11 @@ func GetImageFromFilePath() (image.Image, error) {
|
||||
// ReadUserConfig Reads the user configuration of the Kerberos Open Source instance.
|
||||
// This will return a models.User struct including the username, password,
|
||||
// selected language, and if the installation was completed or not.
|
||||
func ReadUserConfig() (userConfig models.User) {
|
||||
func ReadUserConfig(configDirectory string) (userConfig models.User) {
|
||||
for {
|
||||
jsonFile, err := os.Open("./data/config/user.json")
|
||||
jsonFile, err := os.Open(configDirectory + "/data/config/user.json")
|
||||
if err != nil {
|
||||
log.Log.Error("Config file is not found " + "./data/config/user.json, trying again in 5s: " + err.Error())
|
||||
log.Log.Error("Config file is not found " + configDirectory + "/data/config/user.json, trying again in 5s: " + err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
log.Log.Info("Successfully Opened user.json")
|
||||
@@ -66,7 +66,7 @@ func ReadUserConfig() (userConfig models.User) {
|
||||
return
|
||||
}
|
||||
|
||||
func OpenConfig(configuration *models.Configuration) {
|
||||
func OpenConfig(configDirectory string, configuration *models.Configuration) {
|
||||
|
||||
// We are checking which deployment this is running, so we can load
|
||||
// into the configuration as expected.
|
||||
@@ -146,9 +146,9 @@ func OpenConfig(configuration *models.Configuration) {
|
||||
|
||||
// Open device config
|
||||
for {
|
||||
jsonFile, err := os.Open("./data/config/config.json")
|
||||
jsonFile, err := os.Open(configDirectory + "/data/config/config.json")
|
||||
if err != nil {
|
||||
log.Log.Error("Config file is not found " + "./data/config/config.json" + ", trying again in 5s.")
|
||||
log.Log.Error("Config file is not found " + configDirectory + "/data/config/config.json" + ", trying again in 5s.")
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
log.Log.Info("Successfully Opened config.json from " + configuration.Name)
|
||||
@@ -437,11 +437,11 @@ func OverrideWithEnvironmentVariables(configuration *models.Configuration) {
|
||||
}
|
||||
}
|
||||
|
||||
func SaveConfig(config models.Config, configuration *models.Configuration, communication *models.Communication) error {
|
||||
func SaveConfig(configDirectory string, config models.Config, configuration *models.Configuration, communication *models.Communication) error {
|
||||
if !communication.IsConfiguring.IsSet() {
|
||||
communication.IsConfiguring.Set()
|
||||
|
||||
err := StoreConfig(config)
|
||||
err := StoreConfig(configDirectory, config)
|
||||
if err != nil {
|
||||
communication.IsConfiguring.UnSet()
|
||||
return err
|
||||
@@ -462,7 +462,7 @@ func SaveConfig(config models.Config, configuration *models.Configuration, commu
|
||||
}
|
||||
}
|
||||
|
||||
func StoreConfig(config models.Config) error {
|
||||
func StoreConfig(configDirectory string, config models.Config) error {
|
||||
// Save into database
|
||||
if os.Getenv("DEPLOYMENT") == "factory" || os.Getenv("MACHINERY_ENVIRONMENT") == "kubernetes" {
|
||||
// Write to mongodb
|
||||
@@ -484,7 +484,7 @@ func StoreConfig(config models.Config) error {
|
||||
// Save into file
|
||||
} else if os.Getenv("DEPLOYMENT") == "" || os.Getenv("DEPLOYMENT") == "agent" {
|
||||
res, _ := json.MarshalIndent(config, "", "\t")
|
||||
err := ioutil.WriteFile("./data/config/config.json", res, 0644)
|
||||
err := ioutil.WriteFile(configDirectory+"/data/config/config.json", res, 0644)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/tevino/abool"
|
||||
)
|
||||
|
||||
func Bootstrap(configuration *models.Configuration, communication *models.Communication) {
|
||||
func Bootstrap(configDirectory string, configuration *models.Configuration, communication *models.Communication) {
|
||||
log.Log.Debug("Bootstrap: started")
|
||||
|
||||
// We will keep track of the Kerberos Agent up time
|
||||
@@ -79,7 +79,7 @@ func Bootstrap(configuration *models.Configuration, communication *models.Commun
|
||||
for {
|
||||
|
||||
// This will blocking until receiving a signal to be restarted, reconfigured, stopped, etc.
|
||||
status := RunAgent(configuration, communication, mqttClient, uptimeStart, cameraSettings, decoder, subDecoder)
|
||||
status := RunAgent(configDirectory, configuration, communication, mqttClient, uptimeStart, cameraSettings, decoder, subDecoder)
|
||||
|
||||
if status == "stop" {
|
||||
break
|
||||
@@ -87,7 +87,7 @@ func Bootstrap(configuration *models.Configuration, communication *models.Commun
|
||||
|
||||
if status == "not started" {
|
||||
// We will re open the configuration, might have changed :O!
|
||||
OpenConfig(configuration)
|
||||
OpenConfig(configDirectory, configuration)
|
||||
// We will override the configuration with the environment variables
|
||||
OverrideWithEnvironmentVariables(configuration)
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func Bootstrap(configuration *models.Configuration, communication *models.Commun
|
||||
log.Log.Debug("Bootstrap: finished")
|
||||
}
|
||||
|
||||
func RunAgent(configuration *models.Configuration, communication *models.Communication, mqttClient mqtt.Client, uptimeStart time.Time, cameraSettings *models.Camera, decoder *ffmpeg.VideoDecoder, subDecoder *ffmpeg.VideoDecoder) string {
|
||||
func RunAgent(configDirectory string, configuration *models.Configuration, communication *models.Communication, mqttClient mqtt.Client, uptimeStart time.Time, cameraSettings *models.Camera, decoder *ffmpeg.VideoDecoder, subDecoder *ffmpeg.VideoDecoder) string {
|
||||
|
||||
log.Log.Debug("RunAgent: bootstrapping agent")
|
||||
config := configuration.Config
|
||||
@@ -260,10 +260,10 @@ func RunAgent(configuration *models.Configuration, communication *models.Communi
|
||||
}
|
||||
|
||||
// Handle recording, will write an mp4 to disk.
|
||||
go capture.HandleRecordStream(queue, configuration, communication, streams)
|
||||
go capture.HandleRecordStream(queue, configDirectory, configuration, communication, streams)
|
||||
|
||||
// Handle Upload to cloud provider (Kerberos Hub, Kerberos Vault and others)
|
||||
go cloud.HandleUpload(configuration, communication)
|
||||
go cloud.HandleUpload(configDirectory, configuration, communication)
|
||||
|
||||
// Handle ONVIF actions
|
||||
go onvif.HandleONVIFActions(configuration, communication)
|
||||
@@ -284,7 +284,7 @@ func RunAgent(configuration *models.Configuration, communication *models.Communi
|
||||
(*communication.CancelContext)()
|
||||
|
||||
// We will re open the configuration, might have changed :O!
|
||||
OpenConfig(configuration)
|
||||
OpenConfig(configDirectory, configuration)
|
||||
|
||||
// We will override the configuration with the environment variables
|
||||
OverrideWithEnvironmentVariables(configuration)
|
||||
|
||||
@@ -21,7 +21,7 @@ var Log = Logging{
|
||||
|
||||
var gologging = logging.MustGetLogger("gologger")
|
||||
|
||||
func ConfigureGoLogging(timezone *time.Location) {
|
||||
func ConfigureGoLogging(configDirectory string, timezone *time.Location) {
|
||||
// Logging
|
||||
var format = logging.MustStringFormatter(
|
||||
`%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}`,
|
||||
@@ -32,7 +32,7 @@ func ConfigureGoLogging(timezone *time.Location) {
|
||||
stdBackend := logging.NewLogBackend(os.Stderr, "", 0)
|
||||
stdBackendLeveled := logging.NewBackendFormatter(stdBackend, format)
|
||||
fileBackend := logging.NewLogBackend(&lumberjack.Logger{
|
||||
Filename: "./data/log/machinery.txt",
|
||||
Filename: configDirectory + "/data/log/machinery.txt",
|
||||
MaxSize: 2, // megabytes
|
||||
Compress: true, // disabled by default
|
||||
}, "", 0)
|
||||
@@ -75,10 +75,10 @@ type Logging struct {
|
||||
Level string
|
||||
}
|
||||
|
||||
func (self *Logging) Init(timezone *time.Location) {
|
||||
func (self *Logging) Init(configDirectory string, timezone *time.Location) {
|
||||
switch self.Logger {
|
||||
case "go-logging":
|
||||
ConfigureGoLogging(timezone)
|
||||
ConfigureGoLogging(configDirectory, timezone)
|
||||
case "logrus":
|
||||
ConfigureLogrus(timezone)
|
||||
default:
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/kerberos-io/agent/machinery/src/utils"
|
||||
)
|
||||
|
||||
func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuration *models.Configuration, communication *models.Communication) *gin.RouterGroup {
|
||||
func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirectory string, configuration *models.Configuration, communication *models.Communication) *gin.RouterGroup {
|
||||
|
||||
r.GET("/ws", func(c *gin.Context) {
|
||||
websocket.WebsocketHandler(c, communication)
|
||||
@@ -40,7 +40,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
var config models.Config
|
||||
err := c.BindJSON(&config)
|
||||
if err == nil {
|
||||
err := components.SaveConfig(config, configuration, communication)
|
||||
err := components.SaveConfig(configDirectory, config, configuration, communication)
|
||||
if err == nil {
|
||||
c.JSON(200, gin.H{
|
||||
"data": "☄ Reconfiguring",
|
||||
@@ -78,7 +78,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
}
|
||||
|
||||
// The total number of recordings stored in the directory.
|
||||
recordingDirectory := "./data/recordings"
|
||||
recordingDirectory := configDirectory + "/data/recordings"
|
||||
numberOfRecordings := utils.NumberOfMP4sInDirectory(recordingDirectory)
|
||||
|
||||
// All days stored in this agent.
|
||||
@@ -115,7 +115,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
if eventFilter.NumberOfElements == 0 {
|
||||
eventFilter.NumberOfElements = 10
|
||||
}
|
||||
recordingDirectory := "./data/recordings"
|
||||
recordingDirectory := configDirectory + "/data/recordings"
|
||||
files, err := utils.ReadDirectory(recordingDirectory)
|
||||
if err == nil {
|
||||
events := utils.GetSortedDirectory(files)
|
||||
@@ -137,7 +137,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
})
|
||||
|
||||
api.GET("/days", func(c *gin.Context) {
|
||||
recordingDirectory := "./data/recordings"
|
||||
recordingDirectory := configDirectory + "/data/recordings"
|
||||
files, err := utils.ReadDirectory(recordingDirectory)
|
||||
if err == nil {
|
||||
events := utils.GetSortedDirectory(files)
|
||||
@@ -165,7 +165,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
var config models.Config
|
||||
err := c.BindJSON(&config)
|
||||
if err == nil {
|
||||
err := components.SaveConfig(config, configuration, communication)
|
||||
err := components.SaveConfig(configDirectory, config, configuration, communication)
|
||||
if err == nil {
|
||||
c.JSON(200, gin.H{
|
||||
"data": "☄ Reconfiguring",
|
||||
@@ -205,7 +205,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
})
|
||||
|
||||
api.POST("/persistence/verify", func(c *gin.Context) {
|
||||
cloud.VerifyPersistence(c)
|
||||
cloud.VerifyPersistence(c, configDirectory)
|
||||
})
|
||||
|
||||
// Streaming handler
|
||||
@@ -215,7 +215,7 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configuratio
|
||||
// We will only send an image once per second.
|
||||
time.Sleep(time.Second * 1)
|
||||
log.Log.Info("AddRoutes (/stream): reading from MJPEG stream")
|
||||
img, err := components.GetImageFromFilePath()
|
||||
img, err := components.GetImageFromFilePath(configDirectory)
|
||||
return img, err
|
||||
}
|
||||
h := components.StartMotionJPEG(imageFunction, 80)
|
||||
|
||||
@@ -35,7 +35,7 @@ import (
|
||||
// @in header
|
||||
// @name Authorization
|
||||
|
||||
func StartServer(configuration *models.Configuration, communication *models.Communication) {
|
||||
func StartServer(configDirectory string, configuration *models.Configuration, communication *models.Communication) {
|
||||
|
||||
// Initialize REST API
|
||||
r := gin.Default()
|
||||
@@ -57,12 +57,12 @@ func StartServer(configuration *models.Configuration, communication *models.Comm
|
||||
}
|
||||
|
||||
// Add all routes
|
||||
AddRoutes(r, authMiddleware, configuration, communication)
|
||||
AddRoutes(r, authMiddleware, configDirectory, configuration, communication)
|
||||
|
||||
// Update environment variables
|
||||
environmentVariables := "./www/env.js"
|
||||
environmentVariables := configDirectory + "/www/env.js"
|
||||
if os.Getenv("AGENT_MODE") == "demo" {
|
||||
demoEnvironmentVariables := "./www/env.demo.js"
|
||||
demoEnvironmentVariables := configDirectory + "/www/env.demo.js"
|
||||
// Move demo environment variables to environment variables
|
||||
err := os.Rename(demoEnvironmentVariables, environmentVariables)
|
||||
if err != nil {
|
||||
@@ -71,12 +71,14 @@ func StartServer(configuration *models.Configuration, communication *models.Comm
|
||||
}
|
||||
|
||||
// Add static routes to UI
|
||||
r.Use(static.Serve("/", static.LocalFile("./www", true)))
|
||||
r.Use(static.Serve("/dashboard", static.LocalFile("./www", true)))
|
||||
r.Use(static.Serve("/media", static.LocalFile("./www", true)))
|
||||
r.Use(static.Serve("/settings", static.LocalFile("./www", true)))
|
||||
r.Use(static.Serve("/login", static.LocalFile("./www", true)))
|
||||
r.Handle("GET", "/file/*filepath", Files)
|
||||
r.Use(static.Serve("/", static.LocalFile(configDirectory+"/www", true)))
|
||||
r.Use(static.Serve("/dashboard", static.LocalFile(configDirectory+"/www", true)))
|
||||
r.Use(static.Serve("/media", static.LocalFile(configDirectory+"/www", true)))
|
||||
r.Use(static.Serve("/settings", static.LocalFile(configDirectory+"/www", true)))
|
||||
r.Use(static.Serve("/login", static.LocalFile(configDirectory+"/www", true)))
|
||||
r.Handle("GET", "/file/*filepath", func(c *gin.Context) {
|
||||
Files(c, configDirectory)
|
||||
})
|
||||
|
||||
// Run the api on port
|
||||
err = r.Run(":" + configuration.Port)
|
||||
@@ -85,8 +87,8 @@ func StartServer(configuration *models.Configuration, communication *models.Comm
|
||||
}
|
||||
}
|
||||
|
||||
func Files(c *gin.Context) {
|
||||
func Files(c *gin.Context, configDirectory string) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Content-Type", "video/mp4")
|
||||
c.File("./data/recordings" + c.Param("filepath"))
|
||||
c.File(configDirectory + "/data/recordings" + c.Param("filepath"))
|
||||
}
|
||||
|
||||
@@ -5,6 +5,6 @@ import (
|
||||
"github.com/kerberos-io/agent/machinery/src/routers/http"
|
||||
)
|
||||
|
||||
func StartWebserver(configuration *models.Configuration, communication *models.Communication) {
|
||||
http.StartServer(configuration, communication)
|
||||
func StartWebserver(configDirectory string, configuration *models.Configuration, communication *models.Communication) {
|
||||
http.StartServer(configDirectory, configuration, communication)
|
||||
}
|
||||
|
||||
@@ -110,15 +110,15 @@ func CountDigits(i int64) (count int) {
|
||||
return count
|
||||
}
|
||||
|
||||
func CheckDataDirectoryPermissions() error {
|
||||
recordingsDirectory := "./data/recordings"
|
||||
configDirectory := "./data/config"
|
||||
snapshotsDirectory := "./data/snapshots"
|
||||
cloudDirectory := "./data/cloud"
|
||||
func CheckDataDirectoryPermissions(configDirectory string) error {
|
||||
recordingsDirectory := configDirectory + "/data/recordings"
|
||||
configurationDirectory := configDirectory + "/data/config"
|
||||
snapshotsDirectory := configDirectory + "/data/snapshots"
|
||||
cloudDirectory := configDirectory + "/data/cloud"
|
||||
|
||||
err := CheckDirectoryPermissions(recordingsDirectory)
|
||||
if err == nil {
|
||||
err = CheckDirectoryPermissions(configDirectory)
|
||||
err = CheckDirectoryPermissions(configurationDirectory)
|
||||
if err == nil {
|
||||
err = CheckDirectoryPermissions(snapshotsDirectory)
|
||||
if err == nil {
|
||||
|
||||
6
snap/hooks/configure
vendored
Normal file
6
snap/hooks/configure
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
cp -R $SNAP/data $SNAP_COMMON/
|
||||
cp -R $SNAP/www $SNAP_COMMON/
|
||||
cp -R $SNAP/version $SNAP_COMMON/
|
||||
cp -R $SNAP/mp4fragment $SNAP_COMMON/
|
||||
23
snap/snapcraft.yaml
Normal file
23
snap/snapcraft.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
name: kerberosio # you probably want to 'snapcraft register <name>'
|
||||
base: core22 # the base snap is the execution environment for this snap
|
||||
version: '3.0.0' # just for humans, typically '1.2+git' or '1.3.2'
|
||||
summary: A stand-alone open source video surveillance system # 79 char long summary
|
||||
description: |
|
||||
Kerberos Agent is an isolated and scalable video (surveillance) management
|
||||
agent made available as Open Source under the MIT License. This means that
|
||||
all the source code is available for you or your company, and you can use,
|
||||
transform and distribute the source code; as long you keep a reference of
|
||||
the original license. Kerberos Agent can be used for commercial usage.
|
||||
|
||||
grade: stable # stable # must be 'stable' to release into candidate/stable channels
|
||||
confinement: strict # use 'strict' once you have the right plugs and slots
|
||||
environment:
|
||||
GIN_MODE: release
|
||||
apps:
|
||||
agent:
|
||||
command: main -config /var/snap/kerberosio/common
|
||||
plugs: [ network, network-bind ]
|
||||
parts:
|
||||
agent:
|
||||
source: . #https://github.com/kerberos-io/agent/releases/download/21c0e01/agent-amd64.tar
|
||||
plugin: dump
|
||||
@@ -9,9 +9,9 @@ const dev = {
|
||||
ENV: 'dev',
|
||||
// Comment the below lines, when using codespaces or other special DNS names (which you can't control)
|
||||
HOSTNAME: hostname,
|
||||
API_URL: `${protocol}//${hostname}:8080/api`,
|
||||
URL: `${protocol}//${hostname}:8080`,
|
||||
WS_URL: `${websocketprotocol}//${hostname}:8080/ws`,
|
||||
API_URL: `${protocol}//${hostname}:80/api`,
|
||||
URL: `${protocol}//${hostname}:80`,
|
||||
WS_URL: `${websocketprotocol}//${hostname}:80/ws`,
|
||||
MODE: window['env']['mode'],
|
||||
// Uncomment, and comment the above lines, when using codespaces or other special DNS names (which you can't control)
|
||||
// HOSTNAME: externalHost,
|
||||
|
||||
Reference in New Issue
Block a user