Compare commits

...

76 Commits

Author SHA1 Message Date
Cédric Verstraeten
9e3d705c6f Merge pull request #150 from kerberos-io/fix/align-pts2-webrtc
Fix/align pts2 webrtc
2025-01-02 17:20:59 +01:00
Cedric Verstraeten
1004731903 increase gop size 2025-01-02 17:18:06 +01:00
Cedric Verstraeten
9f2ec91688 Update main.go 2025-01-02 16:56:58 +01:00
Cedric Verstraeten
185135ed94 add legacy timing for MP4 2025-01-02 16:55:58 +01:00
Cedric Verstraeten
27e7d98c68 align with PTS2 2025-01-02 16:40:24 +01:00
Cedric Verstraeten
79f56771e3 align with pts2 2025-01-02 16:34:22 +01:00
Cedric Verstraeten
a7839147d6 Update main.go 2024-10-23 22:28:42 +02:00
Cedric Verstraeten
834d82d532 upgrade to webrtc v4, keep writing to track 2024-10-23 22:26:34 +02:00
Cedric Verstraeten
989f2f5943 commit new dependencies 2024-10-23 20:38:18 +02:00
Cedric Verstraeten
3af1df5b19 set realtime processing to false 2024-10-23 16:08:29 +02:00
Cedric Verstraeten
acf06e6e63 fix database client #2 2024-10-21 20:44:31 +02:00
Cedric Verstraeten
3f43e15cc2 fix database client 2024-10-21 20:41:31 +02:00
Cedric Verstraeten
c14683ec0d update database client 2024-10-18 15:48:04 +02:00
Cédric Verstraeten
213aaa5c15 update agent to 3.2.3 2024-09-14 19:34:19 +02:00
Cedric Verstraeten
9fb00c32d5 hotfix: revert webrtc version (stream broken) 2024-08-27 23:47:58 +02:00
Cedric Verstraeten
57ec08066c upgrade dependencies 2024-08-27 12:43:30 +02:00
Cedric Verstraeten
e0c6375261 IO fix: workaround for ONVIF event system 2024-08-25 20:27:46 +02:00
Cedric Verstraeten
79205abe29 keep the release notes 2024-08-21 10:42:47 +02:00
Cedric Verstraeten
24326558d0 only run release build on creation 2024-08-21 10:30:45 +02:00
Cedric Verstraeten
3f981c0f2f Update docker.yml 2024-08-21 10:26:21 +02:00
Cedric Verstraeten
b6eb7b8317 do not create a tag as github will do it 2024-08-21 10:20:20 +02:00
Cedric Verstraeten
4267ae6305 Update docker.yml 2024-08-21 10:18:33 +02:00
Cedric Verstraeten
0cb40bd93a Update docker.yml 2024-08-21 10:18:14 +02:00
Cedric Verstraeten
d2a8890a43 refactory github actions 2024-08-21 10:13:18 +02:00
Cedric Verstraeten
e5a5a5326b Update docker.yml 2024-08-21 10:10:35 +02:00
Cedric Verstraeten
61febd55c8 Update docker.yml 2024-08-21 10:09:15 +02:00
Cedric Verstraeten
3eac752654 Update docker.yml 2024-08-21 10:08:12 +02:00
Cedric Verstraeten
df4f1863fc use different release approach 2024-08-21 10:06:03 +02:00
Cedric Verstraeten
acee2784d3 improvement for IO's: detection for avigilon and axis cameras 2024-08-21 10:03:01 +02:00
Cedric Verstraeten
8ecb2f94a9 reference deployment guide on top of readme 2024-08-17 07:46:06 +02:00
Cedric Verstraeten
8657baf641 add architecture and reference deployments repo 2024-08-17 07:41:01 +02:00
Cedric Verstraeten
13d1948c9f Revert "test: add pkttimestamp and timestamp to samples to improve WebRTC streaming"
This reverts commit b067758915.
2024-08-14 14:05:22 +02:00
Cédric Verstraeten
8e8d51b719 Update README.md - add slack link 2024-08-12 22:53:45 +02:00
Cedric Verstraeten
ca2413363e [release] v3.1.9 2024-08-04 10:19:43 +02:00
Cedric Verstraeten
b067758915 test: add pkttimestamp and timestamp to samples to improve WebRTC streaming 2024-08-04 10:15:01 +02:00
Cédric Verstraeten
b2b8485b28 add networks 2024-07-24 12:35:09 +02:00
Kilian
c69d635431 Update docker-compose.yaml
Update example docker compose file
2024-07-05 15:50:30 +02:00
Cedric Verstraeten
a305ca36ce move vslaunch to top level and add react launcher 2024-07-05 13:35:33 +02:00
Cedric Verstraeten
a6a97b09f0 update devcontainer 2024-07-05 12:58:53 +02:00
Cédric Verstraeten
4d17a15633 Merge pull request #143 from KilianBoute/patch-1
Update README.md
2024-07-04 12:33:06 +02:00
Cédric Verstraeten
5fdb4b712e Merge pull request #142 from ghosty2004/master
Add Romanian language
2024-07-04 12:21:41 +02:00
Kilian
3d39251ac6 Update README.md 2024-07-04 11:42:05 +02:00
Cedric Verstraeten
9e59cd1596 add support for opus + update dependencies ho mod 2024-06-30 19:44:13 +02:00
ghosty2004
0ada943699 Add Romanian language 2024-06-26 21:04:02 +03:00
Cedric Verstraeten
ecadf7a4db add realtime processing endpoint 2024-06-11 22:47:01 +02:00
Cedric Verstraeten
413ed12fe2 deprecate older version 2024-05-05 22:33:38 +02:00
Cedric Verstraeten
6195fa5b9c upgrade go version to 1.22.2 2024-05-05 22:31:35 +02:00
Cedric Verstraeten
d31524ae52 upgrade go1.22.2 + webrtc/sdp libraries 2024-05-05 22:24:09 +02:00
Cédric Verstraeten
472a40a5f6 add extra space to run command 2024-04-06 11:50:11 +02:00
Cedric Verstraeten
fb9de04002 update dependencies + retry for ONVIF authentication 2024-03-17 11:07:15 +01:00
Cédric Verstraeten
3f29d1c46f fix wrong docker command 2024-01-30 20:47:13 +01:00
Cedric Verstraeten
b67a72ba9a [release] v3.1.8 2024-01-30 13:26:44 +01:00
Cedric Verstraeten
8fc9bc264d feature: add camera friendly name to UI 2024-01-30 11:21:58 +01:00
Cedric Verstraeten
b2589f498d hot-fix: embed friendly name in recording when set 2024-01-30 10:56:31 +01:00
Cedric Verstraeten
b1ff5134f2 feature: add double encryption
we are now encrypting to Kerberos Hub by default, secondary encryption can be added through bring your own encryption keys.

all encryption can be turned on/off if required
2024-01-17 20:53:42 +01:00
Cedric Verstraeten
3551d02d50 feature: add ability to force TURN server 2024-01-17 09:44:24 +01:00
Cedric Verstraeten
4c413012a4 [release] v3.1.7 2024-01-16 13:02:41 +01:00
Cedric Verstraeten
74ea2f6cdd hot-fix: make sure webrtc candidates are assigned to the correct session 2024-01-16 12:55:31 +01:00
Cedric Verstraeten
2a7d9b62d4 warning: printing the work sub url 2024-01-16 10:49:40 +01:00
Cedric Verstraeten
21d81b94dd [release] v3.1.6 2024-01-16 09:47:07 +01:00
Cedric Verstraeten
091662ff26 hot-fix: support avigilon backchannel 2024-01-16 09:39:34 +01:00
Cedric Verstraeten
803e8f55ef correct webrtc audio buffer duration 2024-01-14 21:37:58 +01:00
Cedric Verstraeten
14d38ecf08 [release] v3.1.5 2024-01-12 15:28:48 +01:00
Cedric Verstraeten
34d945055b Update main.go 2024-01-12 11:49:44 +01:00
Cedric Verstraeten
8c44da8233 hide passwords in ui + skip empty decode frames 2024-01-12 11:47:08 +01:00
Cédric Verstraeten
a8b79947ef Update README.md 2024-01-12 09:53:38 +01:00
Cedric Verstraeten
7c653f809d upgrqde dependencies + move file (decap) 2024-01-11 23:05:46 +01:00
Cedric Verstraeten
49f1603f40 align more blocking methods 2024-01-11 22:43:16 +01:00
Cedric Verstraeten
b4369ea932 improve non-blocking approve for agents tend to restart for some strange reason 2024-01-11 22:35:56 +01:00
Cedric Verstraeten
83ba7baa4b [release] v3.1.4
- hot-fix: preserve width and height of both main and sub stream
2024-01-10 17:06:49 +01:00
Cedric Verstraeten
9339ae30fd [release] v3.1.3 2024-01-10 16:30:20 +01:00
Cedric Verstraeten
c18f2bd445 remove file logger 2024-01-10 16:29:37 +01:00
Cedric Verstraeten
319876bbb0 hot-fix: onvif pull message might be empty 2024-01-10 16:28:40 +01:00
Cedric Verstraeten
442ba97c61 [release] v3.1.2
hot-fix: for missing SPS and PPS from opening codec.
2024-01-09 13:13:42 +01:00
Cedric Verstraeten
00e0b0b547 hot fix: capture SSP and PPS in a later decode, it might not be provided at the initialization, and keep it up to date. 2024-01-09 12:07:32 +01:00
Cedric Verstraeten
145f478249 go mod - upgrade dependencies 2024-01-08 13:08:33 +01:00
59 changed files with 4882 additions and 1037 deletions

View File

@@ -1,2 +1,2 @@
FROM kerberos/devcontainer:0a50dc9
FROM kerberos/devcontainer:5da0fe7
LABEL AUTHOR=Kerberos.io

View File

@@ -1,33 +1,21 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/docker-existing-dockerfile
{
"name": "A Dockerfile containing FFmpeg, OpenCV, Go and Yarn",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "./Dockerfile",
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
3000,
80
],
// Uncomment the next line to run commands after the container is created - for example installing curl.
"postCreateCommand": "cd ui && yarn install && yarn build && cd ../machinery && go mod download",
"features": {
"ghcr.io/devcontainers-contrib/features/ansible:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-kubernetes-tools.vscode-kubernetes-tools",
"GitHub.copilot"
"ms-azuretools.vscode-docker",
"GitHub.copilot",
"golang.go",
"ms-vscode.vscode-typescript-next"
]
}
},
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
// "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}
}

View File

@@ -2,61 +2,57 @@ name: Docker development build
on:
push:
branches: [ develop ]
branches: [develop]
jobs:
build-amd64:
# If contains the keyword "#release" in the commit message.
if: ${{ !contains(github.event.head_commit.message, '#release') }}
runs-on: ubuntu-latest
strategy:
matrix:
architecture: [amd64]
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: docker buildx imagetools create -t kerberos/agent-dev:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Create new and append to latest manifest
run: docker buildx imagetools create -t kerberos/agent-dev:latest kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: docker buildx imagetools create -t kerberos/agent-dev:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Create new and append to latest manifest
run: docker buildx imagetools create -t kerberos/agent-dev:latest kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
build-other:
# If contains the keyword "#release" in the commit message.
if: ${{ !contains(github.event.head_commit.message, '#release') }}
runs-on: ubuntu-latest
strategy:
matrix:
#architecture: [arm64, arm/v7, arm/v6]
architecture: [arm64, arm/v7]
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: docker buildx imagetools create --append -t kerberos/agent-dev:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Create new and append to manifest latest
run: docker buildx imagetools create --append -t kerberos/agent-dev:latest kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: docker buildx imagetools create --append -t kerberos/agent-dev:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Create new and append to manifest latest
run: docker buildx imagetools create --append -t kerberos/agent-dev:latest kerberos/agent-dev:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)

View File

@@ -7,13 +7,11 @@ on:
jobs:
build-amd64:
# If contains the keyword "[release]" in the commit message.
if: "contains(github.event.head_commit.message, '[release]')"
runs-on: ubuntu-latest
strategy:
matrix:
architecture: [amd64]
steps:
runs-on: ubuntu-latest
strategy:
matrix:
architecture: [amd64]
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
@@ -28,31 +26,29 @@ jobs:
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: cd agent && docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
run: cd agent && docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: cd agent && docker buildx imagetools create -t kerberos/agent-nightly:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
build-other:
# If contains the keyword "[release]" in the commit message.
if: "contains(github.event.head_commit.message, '[release]')"
runs-on: ubuntu-latest
strategy:
matrix:
architecture: [arm64, arm/v7, arm/v6]
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
run: git clone https://github.com/kerberos-io/agent && cd agent
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: cd agent && docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: cd agent && docker buildx imagetools create --append -t kerberos/agent-nightly:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
run: git clone https://github.com/kerberos-io/agent && cd agent
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: cd agent && docker buildx build --platform linux/${{matrix.architecture}} -t kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7) --push .
- name: Create new and append to manifest
run: cd agent && docker buildx imagetools create --append -t kerberos/agent-nightly:$(echo $GITHUB_SHA | cut -c1-7) kerberos/agent-nightly:arch-$(echo ${{matrix.architecture}} | tr / -)-$(echo $GITHUB_SHA | cut -c1-7)

View File

@@ -1,17 +1,14 @@
name: Docker master build
name: Docker release build
on:
push:
# If pushed to master branch.
branches: [ master ]
release:
types: [created]
env:
REPO: kerberos/agent
jobs:
build-amd64:
# If contains the keyword "[release]" in the commit message.
if: "contains(github.event.head_commit.message, '[release]')"
runs-on: ubuntu-latest
permissions:
contents: write
@@ -37,26 +34,24 @@ jobs:
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}} --push .
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}} --push .
- name: Create new and append to manifest
run: docker buildx imagetools create -t $REPO:${{ steps.short-sha.outputs.sha }} $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}}
run: docker buildx imagetools create -t $REPO:${{ github.ref_name }} $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}}
- name: Create new and append to manifest latest
run: docker buildx imagetools create -t $REPO:latest $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}}
run: docker buildx imagetools create -t $REPO:latest $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}}
- name: Run Buildx with output
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 .
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-$(echo ${{matrix.architecture}} | tr / -)-${{github.ref_name}} --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 }}
message: "Release ${{ steps.short-sha.outputs.sha }}"
- name: Create a release
- name: Create a release
uses: ncipollo/release-action@v1
with:
latest: true
name: ${{ steps.short-sha.outputs.sha }}
tag: ${{ steps.short-sha.outputs.sha }}
allowUpdates: true
name: ${{ github.ref_name }}
tag: ${{ github.ref_name }}
generateReleaseNotes: false
omitBodyDuringUpdate: true
artifacts: "agent-${{matrix.architecture}}.tar"
# Taken from GoReleaser's own release workflow.
# The available Snapcraft Action has some bugs described in the issue below.
@@ -68,10 +63,8 @@ jobs:
# mkdir -p $HOME/.cache/snapcraft/download
# mkdir -p $HOME/.cache/snapcraft/stage-packages
#- name: Use Snapcraft
# run: tar -xf agent-${{matrix.architecture}}.tar && snapcraft
# run: tar -xf agent-${{matrix.architecture}}.tar && snapcraft
build-other:
# If contains the keyword "[release]" in the commit message.
if: "contains(github.event.head_commit.message, '[release]')"
runs-on: ubuntu-latest
permissions:
contents: write
@@ -81,39 +74,40 @@ jobs:
architecture: [arm64, arm-v7, arm-v6]
#architecture: [arm64, arm-v7]
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- uses: benjlevesque/short-sha@v2.1
id: short-sha
with:
length: 7
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}} --push .
- name: Create new and append to manifest
run: docker buildx imagetools create --append -t $REPO:${{ steps.short-sha.outputs.sha }} $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}}
- name: Create new and append to manifest latest
run: docker buildx imagetools create --append -t $REPO:latest $REPO-arch:arch-${{matrix.architecture}}-${{steps.short-sha.outputs.sha}}
- name: Run Buildx with output
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
- name: Create a release
uses: ncipollo/release-action@v1
with:
latest: true
allowUpdates: true
name: ${{ steps.short-sha.outputs.sha }}
tag: ${{ steps.short-sha.outputs.sha }}
artifacts: "agent-${{matrix.architecture}}.tar"
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
- uses: benjlevesque/short-sha@v2.1
id: short-sha
with:
length: 7
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Run Buildx
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}} --push .
- name: Create new and append to manifest
run: docker buildx imagetools create --append -t $REPO:${{ github.ref_name }} $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}}
- name: Create new and append to manifest latest
run: docker buildx imagetools create --append -t $REPO:latest $REPO-arch:arch-${{matrix.architecture}}-${{github.ref_name}}
- name: Run Buildx with output
run: docker buildx build --platform linux/$(echo ${{matrix.architecture}} | tr - /) -t $REPO-arch:arch-$(echo ${{matrix.architecture}} | tr / -)-${{github.ref_name}} --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
- name: Create a release
uses: ncipollo/release-action@v1
with:
latest: true
allowUpdates: true
name: ${{ github.ref_name }}
tag: ${{ github.ref_name }}
generateReleaseNotes: false
omitBodyDuringUpdate: true
artifacts: "agent-${{matrix.architecture}}.tar"

View File

@@ -2,37 +2,37 @@ name: Go
on:
push:
branches: [ develop, master ]
branches: [develop, master]
pull_request:
branches: [ develop, master ]
branches: [develop, master]
jobs:
build:
name: Build
runs-on: ubuntu-latest
container:
image: kerberos/base:0a50dc9
image: kerberos/base:eb6b088
strategy:
matrix:
#No longer supported Go versions.
#go-version: ['1.17', '1.18', '1.19']
go-version: ['1.20', '1.21']
#go-version: ['1.17', '1.18', '1.19', '1.20', '1.21']
go-version: ["1.22"]
steps:
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Check out code into the Go module directory
uses: actions/checkout@v4
- name: Set up git ownershi
run: git config --system --add safe.directory /__w/agent/agent
- name: Get dependencies
run: cd machinery && go mod download
- name: Build
run: cd machinery && go build -v ./...
- name: Vet
run: cd machinery && go vet -v ./...
- name: Test
run: cd machinery && go test -v ./...
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Check out code into the Go module directory
uses: actions/checkout@v4
- name: Set up git ownershi
run: git config --system --add safe.directory /__w/agent/agent
- name: Get dependencies
run: cd machinery && go mod download
- name: Build
run: cd machinery && go build -v ./...
- name: Vet
run: cd machinery && go vet -v ./...
- name: Test
run: cd machinery && go test -v ./...

1
.gitignore vendored
View File

@@ -11,4 +11,5 @@ machinery/data/snapshots
machinery/test*
machinery/init-dev.sh
machinery/.env
machinery/vendor
deployments/docker/private-docker-compose.yaml

31
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,31 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Golang",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/machinery/main.go",
"args": [
"-action",
"run"
],
"envFile": "${workspaceFolder}/machinery/.env",
"buildFlags": "--tags dynamic",
},
{
"name": "Launch React",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/ui",
"runtimeExecutable": "yarn",
"runtimeArgs": [
"start"
],
}
]
}

View File

@@ -1,5 +1,5 @@
FROM kerberos/base:0a50dc9 AS build-machinery
FROM kerberos/base:eb6b088 AS build-machinery
LABEL AUTHOR=Kerberos.io
ENV GOROOT=/usr/local/go

View File

@@ -17,11 +17,14 @@
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
[![donate](https://brianmacdonald.github.io/Ethonate/svg/eth-donate-blue.svg)](https://brianmacdonald.github.io/Ethonate/address#0xf4a759C9436E2280Ea9cdd23d3144D95538fF4bE)
<a target="_blank" href="https://twitter.com/kerberosio?ref_src=twsrc%5Etfw"><img src="https://img.shields.io/twitter/url.svg?label=Follow%20%40kerberosio&style=social&url=https%3A%2F%2Ftwitter.com%2Fkerberosio" alt="Twitter Widget"></a>
[![Discord Shield](https://discordapp.com/api/guilds/1039619181731135499/widget.png?style=shield)](https://discord.gg/Bj77Vqfp2G)
[![kerberosio](https://snapcraft.io/kerberosio/badge.svg)](https://snapcraft.io/kerberosio)
[![Slack invite](https://img.shields.io/badge/join%20kerberos.io%20on%20slack-grey?style=for-the-badge&logo=slack)](https://joinslack.kerberos.io/)
[**Docker Hub**](https://hub.docker.com/r/kerberos/agent) | [**Documentation**](https://doc.kerberos.io) | [**Website**](https://kerberos.io) | [**View Demo**](https://demo.kerberos.io)
> Before you continue, this repository discusses one of the components of the Kerberos.io stack, the Kerberos Agent, in depth. If you are [looking for an end-to-end deployment guide have a look here](https://github.com/kerberos-io/deployment).
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 (which was not the case for v2). Read more [about the license here](LICENSE).
![Kerberos Agent go through UI](./assets/img/kerberos-agent-overview.gif)
@@ -30,7 +33,7 @@ Kerberos Agent is an isolated and scalable video (surveillance) management agent
- An IP camera which supports a RTSP H264 or H265 encoded stream,
- (or) a USB camera, Raspberry Pi camera or other camera, that [you can transform to a valid RTSP H264 or H265 stream](https://github.com/kerberos-io/camera-to-rtsp).
- Any hardware (ARMv6, ARMv7, ARM64, AMD) that can run a binary or container, for example: a Raspberry Pi, NVidia Jetson, Intel NUC, a VM, Bare metal machine or a full blown Kubernetes cluster.
- Any hardware (ARMv6, ARMv7, ARM64, AMD64) that can run a binary or container, for example: a Raspberry Pi, NVidia Jetson, Intel NUC, a VM, Bare metal machine or a full blown Kubernetes cluster.
## :video_camera: Is my camera working?
@@ -64,8 +67,8 @@ There are a myriad of cameras out there (USB, IP and other cameras), and it migh
1. [Contribute with Codespaces](#contribute-with-codespaces)
2. [Develop and build](#develop-and-build)
3. [Building from source](#building-from-source)
4. [Building for Docker](#building-for-docker)
3. [Building from source](#building-from-source)
4. [Building for Docker](#building-for-docker)
### Varia
@@ -75,17 +78,17 @@ There are a myriad of cameras out there (USB, IP and other cameras), and it migh
## Quickstart - Docker
The easiest to get your Kerberos Agent up and running is to use our public image on [Docker hub](https://hub.docker.com/r/kerberos/agent). Once you have selected a specific tag, run below `docker` command, which will open the web interface of your Kerberos agent on port `80`, and off you go. For a more configurable and persistent deployment have a look at [Running and automating a Kerberos Agent](#running-and-automating-a-kerberos-agent).
The easiest way to get your Kerberos Agent up and running is to use our public image on [Docker hub](https://hub.docker.com/r/kerberos/agent). Once you have selected a specific tag, run `docker` command below, which will open the web interface of your Kerberos agent on port `80`, and off you go. For a more configurable and persistent deployment have a look at [Running and automating a Kerberos Agent](#running-and-automating-a-kerberos-agent).
docker run -p 80:80 --name mycamera -d --restart=always kerberos/agent:latest
If you want to connect to an USB or Raspberry Pi camera, [you'll need to run our side car container](https://github.com/kerberos-io/camera-to-rtsp) which proxy the camera to an RTSP stream. In that case you'll want to configure the Kerberos Agent container to run in the host network, so it can connect directly to the RTSP sidecar.
If you want to connect to a USB or Raspberry Pi camera, [you'll need to run our side car container](https://github.com/kerberos-io/camera-to-rtsp) which proxies the camera to an RTSP stream. In that case you'll want to configure the Kerberos Agent container to run in the host network, so it can connect directly to the RTSP sidecar.
docker run --network=host --name mycamera -d --restart=always kerberos/agent:latest
## Quickstart - Balena
Run Kerberos Agent with [Balena Cloud](https://www.balena.io/) super powers. Monitor your Kerberos Agent with seamless remote access, over the air updates, an encrypted public `https` endpoint and many more. Checkout our application `video-surveillance` on [Balena Hub](https://hub.balena.io/apps/2064752/video-surveillance), and create your first or fleet of Kerberos Agent(s).
Run Kerberos Agent with [Balena Cloud](https://www.balena.io/) super powers. Monitor your Kerberos Agent with seamless remote access, over the air updates, an encrypted public `https` endpoint and much more. Checkout our application `video-surveillance` on [Balena Hub](https://hub.balena.io/apps/2064752/video-surveillance), and create your first or fleet of Kerberos Agent(s).
[![deploy with balena](https://balena.io/deploy.svg)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/kerberos-io/balena-agent)
@@ -101,15 +104,17 @@ Once installed you can find your Kerberos Agent configration at `/var/snap/kerbe
## A world of Kerberos Agents
The Kerberos Agent is an isolated and scalable video (surveillance) management agent with a strong focus on user experience, scalability, resilience, extension and integration. Next to the Kerberos Agent, Kerberos.io provides many other tools such as [Kerberos Factory](https://github.com/kerberos-io/factory), [Kerberos Vault](https://github.com/kerberos-io/vault) and [Kerberos Hub](https://github.com/kerberos-io/hub) to provide additional capabilities: bring your own cloud, bring your own storage, central overview, live streaming, machine learning etc.
The Kerberos Agent is an isolated and scalable video (surveillance) management agent with a strong focus on user experience, scalability, resilience, extension and integration. Next to the Kerberos Agent, Kerberos.io provides many other tools such as [Kerberos Factory](https://github.com/kerberos-io/factory), [Kerberos Vault](https://github.com/kerberos-io/vault), and [Kerberos Hub](https://github.com/kerberos-io/hub) to provide additional capabilities: bring your own cloud, bring your own storage, central overview, live streaming, machine learning, etc.
As mentioned above Kerberos.io applies the concept of agents. An agent is running next to (or on) your camera, and is processing a single camera feed. It applies motion based or continuous recording and make those recordings available through a user friendly web interface. A Kerberos Agent allows you to connect to other cloud services or integrates with custom applications. Kerberos Agent is used for personal usage and scales to enterprise production level deployments.
[![Deployment Agent](./assets/img/edge-deployment-agent.svg)](https://github.com/kerberos-io/deployment)
As mentioned above Kerberos.io applies the concept of agents. An agent is running next to (or on) your camera, and is processing a single camera feed. It applies motion based or continuous recording and makes those recordings available through a user friendly web interface. A Kerberos Agent allows you to connect to other cloud services or integrate with custom applications. Kerberos Agent is used for personal applications and scales to enterprise production level deployments. Learn more about the [deployment strategies here](<(https://github.com/kerberos-io/deployment)>).
This repository contains everything you'll need to know about our core product, Kerberos Agent. Below you'll find a brief list of features and functions.
- Low memory and CPU usage.
- Simplified and modern user interface.
- Multi architecture (ARMv7, ARMv8, amd64, etc).).
- Multi architecture (ARMv6, ARMv7, ARM64, AMD64)
- Multi stream, for example recording in H265, live streaming and motion detection in H264.
- Multi camera support: IP Cameras (H264 and H265), USB cameras and Raspberry Pi Cameras [through a RTSP proxy](https://github.com/kerberos-io/camera-to-rtsp).
- Single camera per instance (e.g. one container per camera).
@@ -129,7 +134,7 @@ This repository contains everything you'll need to know about our core product,
## How to run and deploy a Kerberos Agent
As described before a Kerberos Agent is a container, which can be deployed through various ways and automation tools such as `docker`, `docker compose`, `kubernetes` and the list goes on. To simplify your life we have come with concrete and working examples of deployments to help you speed up your Kerberos.io journey.
A Kerberos Agent, as previously mentioned, is a container. You can deploy it using various methods and automation tools, including `docker`, `docker compose`, `kubernetes` and more. To streamline your Kerberos.io experience, we provide concrete deployment examples to speed up your Kerberos.io journey
We have documented the different deployment models [in the `deployments` directory](https://github.com/kerberos-io/agent/tree/master/deployments) of this repository. There you'll learn and find how to deploy using:
@@ -143,7 +148,7 @@ We have documented the different deployment models [in the `deployments` directo
- [Balena](https://github.com/kerberos-io/agent/tree/master/deployments#8-balena)
- [Snap](https://github.com/kerberos-io/agent/tree/master/deployments#9-snap)
By default your Kerberos Agents will store all its configuration and recordings inside the container. To help you automate and have a more consistent data governance, you can attach volumes to configure and persist data of your Kerberos Agents, and/or configure each Kerberos Agent through environment variables.
By default, your Kerberos Agents store all configuration and recordings within the container. To help you automate and have a more consistent data governance, you can attach volumes to configure and persist data of your Kerberos Agents and/or configure each Kerberos Agent through environment variables.
## Access the Kerberos Agent
@@ -158,23 +163,23 @@ The default username and password for the Kerberos Agent is:
## Configure and persist with volume mounts
An example of how to mount a host directory is shown below using `docker`, but is applicable for [all the deployment models and tools described above](#running-and-automating-a-kerberos-agent).
An example of how to mount a host directory is shown below using `docker`, but is applicable for [all of the deployment models and tools described above](#running-and-automating-a-kerberos-agent).
You attach a volume to your container by leveraging the `-v` option. To mount your own configuration file and recordings folder, execute as following:
You attach a volume to your container by leveraging the `-v` option. To mount your own configuration file and recordings folder, run the following commands:
docker run -p 80:80 --name mycamera \
-v $(pwd)/agent/config:/home/agent/data/config \
-v $(pwd)/agent/recordings:/home/agent/data/recordings \
-d --restart=always kerberos/agent:latest
More example [can be found in the deployment section](https://github.com/kerberos-io/agent/tree/master/deployments) for each deployment and automation tool. Please note to verify the permissions of the directory/volume you are attaching. More information in [this issue](https://github.com/kerberos-io/agent/issues/80).
More examples for each deployment and automation tool [can be found in the deployment section](https://github.com/kerberos-io/agent/tree/master/deployments). Be sure to verify the permissions of the directory/volume you are attaching. More information in [this issue](https://github.com/kerberos-io/agent/issues/80).
chmod -R 755 kerberos-agent/
chown 100:101 kerberos-agent/ -R
## Configure with environment variables
Next to attaching the configuration file, it is also possible to override the configuration with environment variables. This makes deployments easier when leveraging `docker compose` or `kubernetes` deployments much easier and scalable. Using this approach we simplify automation through `ansible` and `terraform`.
Next to attaching the configuration file, it is also possible to override the configuration with environment variables. This makes deploying with `docker compose` or `kubernetes` much easier and more scalable. Using this approach, we simplify automation through `ansible` and `terraform`.
docker run -p 80:80 --name mycamera \
-e AGENT_NAME=mycamera \
@@ -197,7 +202,7 @@ Next to attaching the configuration file, it is also possible to override the co
| `AGENT_REMOVE_AFTER_UPLOAD` | When enabled, recordings uploaded successfully to a storage will be removed from disk. | "true" |
| `AGENT_OFFLINE` | Makes sure no external connection is made. | "false" |
| `AGENT_AUTO_CLEAN` | Cleans up the recordings directory. | "true" |
| `AGENT_AUTO_CLEAN_MAX_SIZE` | If `AUTO_CLEAN` enabled, set the max size of the recordings directory in (MB). | "100" |
| `AGENT_AUTO_CLEAN_MAX_SIZE` | If `AUTO_CLEAN` enabled, set the max size of the recordings directory (in MB). | "100" |
| `AGENT_TIME` | Enable the timetable for Kerberos Agent | "false" |
| `AGENT_TIMETABLE` | A (weekly) time table to specify when to make recordings "start1,end1,start2,end2;start1.. | "" |
| `AGENT_REGION_POLYGON` | A single polygon set for motion detection: "x1,y1;x2,y2;x3,y3;... | "" |
@@ -212,20 +217,23 @@ Next to attaching the configuration file, it is also possible to override the co
| `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 "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_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" |
| `AGENT_CAPTURE_PIXEL_CHANGE` | If `CONTINUOUS` set to `false`, the number of pixel require to change before motion triggers. | "150" |
| `AGENT_CAPTURE_FRAGMENTED` | Set the format of the recorded MP4 to fragmented (suitable for HLS). | "false" |
| `AGENT_CAPTURE_FRAGMENTED_DURATION` | If `AGENT_CAPTURE_FRAGMENTED` set to `true`, define the duration (seconds) of a fragment. | "8" |
| `AGENT_MQTT_URI` | A MQTT broker endpoint that is used for bi-directional communication (live view, onvif, etc) | "tcp://mqtt.kerberos.io:1883" |
| `AGENT_MQTT_URI` | An MQTT broker endpoint that is used for bi-directional communication (live view, onvif, etc) | "tcp://mqtt.kerberos.io:1883" |
| `AGENT_MQTT_USERNAME` | Username of the MQTT broker. | "" |
| `AGENT_MQTT_PASSWORD` | Password of the MQTT broker. | "" |
| `AGENT_REALTIME_PROCESSING` | If `AGENT_REALTIME_PROCESSING` set to `true`, the agent will send key frames to the topic | "" |
| `AGENT_REALTIME_PROCESSING_TOPIC` | The topic to which keyframes will be sent in base64 encoded format. | "" |
| `AGENT_STUN_URI` | When using WebRTC, you'll need to provide a STUN server. | "stun:turn.kerberos.io:8443" |
| `AGENT_FORCE_TURN` | Force using a TURN server, by generating relay candidates only. | "false" |
| `AGENT_TURN_URI` | When using WebRTC, you'll need to provide a TURN server. | "turn:turn.kerberos.io:8443" |
| `AGENT_TURN_USERNAME` | TURN username used for WebRTC. | "username1" |
| `AGENT_TURN_PASSWORD` | TURN password used for WebRTC. | "password1" |
| `AGENT_CLOUD` | Store recordings in Kerberos Hub (s3), Kerberos Vault (kstorage) or Dropbox (dropbox). | "s3" |
| `AGENT_CLOUD` | Store recordings in Kerberos Hub (s3), Kerberos Vault (kstorage), or Dropbox (dropbox). | "s3" |
| `AGENT_HUB_ENCRYPTION` | Turning on/off encryption of traffic from your Kerberos Agent to Kerberos Hub. | "true" |
| `AGENT_HUB_URI` | The Kerberos Hub API, defaults to our Kerberos Hub SAAS. | "https://api.hub.domain.com" |
| `AGENT_HUB_KEY` | The access key linked to your account in Kerberos Hub. | "" |
@@ -236,26 +244,26 @@ Next to attaching the configuration file, it is also possible to override the co
| `AGENT_KERBEROSVAULT_ACCESS_KEY` | The access key of a Kerberos Vault account. | "" |
| `AGENT_KERBEROSVAULT_SECRET_KEY` | The secret key of a Kerberos Vault account. | "" |
| `AGENT_KERBEROSVAULT_PROVIDER` | A Kerberos Vault provider you have created (optional). | "" |
| `AGENT_KERBEROSVAULT_DIRECTORY` | The directory, in the provider, where the recordings will be stored in. | "" |
| `AGENT_KERBEROSVAULT_DIRECTORY` | The directory, in the Kerberos vault, where the recordings will be stored. | "" |
| `AGENT_DROPBOX_ACCESS_TOKEN` | The Access Token from your Dropbox app, that is used to leverage the Dropbox SDK. | "" |
| `AGENT_DROPBOX_DIRECTORY` | The directory, in the provider, where the recordings will be stored in. | "" |
| `AGENT_DROPBOX_DIRECTORY` | The directory, in Dropbox, where the recordings will be stored. | "" |
| `AGENT_ENCRYPTION` | Enable 'true' or disable 'false' end-to-end encryption for MQTT messages. | "false" |
| `AGENT_ENCRYPTION_RECORDINGS` | Enable 'true' or disable 'false' end-to-end encryption for recordings. | "false" |
| `AGENT_ENCRYPTION_FINGERPRINT` | The fingerprint of the keypair (public/private keys), so you know which one to use. | "" |
| `AGENT_ENCRYPTION_PRIVATE_KEY` | The private key (assymetric/RSA) to decryptand sign requests send over MQTT. | "" |
| `AGENT_ENCRYPTION_SYMMETRIC_KEY` | The symmetric key (AES) to encrypt and decrypt request send over MQTT. | "" |
| `AGENT_ENCRYPTION_PRIVATE_KEY` | The private key (assymetric/RSA) to decrypt and sign requests send over MQTT. | "" |
| `AGENT_ENCRYPTION_SYMMETRIC_KEY` | The symmetric key (AES) to encrypt and decrypt requests sent over MQTT. | "" |
## Encryption
You can encrypt your recordings and outgoing MQTT messages with your own AES and RSA keys by enabling the encryption settings. Once enabled all your recordings will be encrypted using AES-256-CBC and your symmetric key. You can either use the default `openssl` toolchain to decrypt the recordings with your AES key, as following:
You can encrypt your recordings and outgoing MQTT messages with your own AES and RSA keys by enabling the encryption settings. Once enabled, all your recordings will be encrypted using AES-256-CBC and your symmetric key. You can use the default `openssl` toolchain to decrypt the recordings with your AES key, as following:
openssl aes-256-cbc -d -md md5 -in encrypted.mp4 -out decrypted.mp4 -k your-key-96ab185xxxxxxxcxxxxxxxx6a59c62e8
, and additionally you can decrypt a folder of recordings, using the Kerberos Agent binary as following:
Or you can decrypt a folder of recordings, using the Kerberos Agent binary as following:
go run main.go -action decrypt ./data/recordings your-key-96ab185xxxxxxxcxxxxxxxx6a59c62e8
or for a single file:
Or for a single file:
go run main.go -action decrypt ./data/recordings/video.mp4 your-key-96ab185xxxxxxxcxxxxxxxx6a59c62e8
@@ -264,8 +272,9 @@ or for a single file:
If we talk about video encoders and decoders (codecs) there are 2 major video codecs on the market: H264 and H265. Taking into account your use case, you might use one over the other. We will provide an (not complete) overview of the advantages and disadvantages of each codec in the field of video surveillance and video analytics. If you would like to know more, you should look for additional resources on the internet (or if you like to read physical items, books still exists nowadays).
- H264 (also known as AVC or MPEG-4 Part 10)
- Is the most common one and most widely supported for IP cameras.
- Supported in the majority of browsers, operating system and third-party applications.
- Supported in the majority of browsers, operating system, and third-party applications.
- Can be embedded in commercial and 3rd party applications.
- Different levels of compression (high, medium, low, ..)
- Better quality / compression ratio, shows less artifacts at medium compression ratios.
@@ -279,14 +288,14 @@ If we talk about video encoders and decoders (codecs) there are 2 major video co
- H265 shows artifacts in motion based environments (which is less with H264).
- Recording the same video (resolution, duration and FPS) in H264 and H265 will result in approx 50% the file size.
- Not supported in technologies such as WebRTC
Conclusion: depending on the use case you might choose one over the other, and you can use both at the same time. For example you can use H264 (main stream) for livestreaming, and H265 (sub stream) for recording. If you wish to play recordings in a cross-platform and cross-browser environment, you might opt for H264 for better support.
## Contribute with Codespaces
One of the major blockers for letting you contribute to an Open Source project is to setup your local development machine. Why? Because you might have already some tools and libraries installed that are used for other projects, and the libraries you would need for Kerberos Agent, for example FFmpeg, might require a different version. Welcome to the dependency hell..
One of the major blockers for letting you contribute to an Open Source project is to set up your local development machine. Why? Because you might already have some tools and libraries installed that are used for other projects, and the libraries you would need for Kerberos Agent, for example FFmpeg, might require a different version. Welcome to dependency hell...
By leveraging codespaces, which the Kerberos Agent repo supports, you will be able to setup the required development environment in a few minutes. By opening the `<> Code` tab on the top of the page, you will be able to create a codespace, [using the Kerberos Devcontainer](https://github.com/kerberos-io/devcontainer) base image. This image requires all the relevant dependencies: FFmpeg, OpenCV, Golang, Node, Yarn, etc.
By leveraging codespaces, which the Kerberos Agent repo supports, you will be able to set up the required development environment in a few minutes. By opening the `<> Code` tab on the top of the page, you will be able to create a codespace, [using the Kerberos Devcontainer](https://github.com/kerberos-io/devcontainer) base image. This image requires all the relevant dependencies: FFmpeg, OpenCV, Golang, Node, Yarn, etc.
![Kerberos Agent codespace](assets/img/codespace.png)
@@ -313,7 +322,7 @@ On opening of the GitHub Codespace, some dependencies will be installed. Once th
WS_URL: `${websocketprotocol}//${externalHost}/ws`,
};
Go and open two terminals one for the `ui` project and one for the `machinery` project.
Go and open two terminals: one for the `ui` project and one for the `machinery` project.
1. Terminal A:
@@ -329,11 +338,11 @@ Once executed, a popup will show up mentioning `portforwarding`. You should see
![Codespace make public](./assets/img/codespace-make-public.png)
As mentioned above, copy the hostname of the `machinery` DNS name, and past it in the `ui/src/config.json` file. Once done reload, the `ui` page in your browser, and you should be able to access the login page with the default credentials `root` and `root`.
As mentioned above, copy the hostname of the `machinery` DNS name, and paste it in the `ui/src/config.json` file. Once done, reload the `ui` page in your browser, and you should be able to access the login page with the default credentials `root` and `root`.
## Develop and build
Kerberos Agent is divided in two parts a `machinery` and `web`. Both parts live in this repository in their relative folders. For development or running the application on your local machine, you have to run both the `machinery` and the `web` as described below. When running in production everything is shipped as only one artifact, read more about this at [Building for production](#building-for-production).
The Kerberos Agent is divided in two parts: a `machinery` and `web` part. Both parts live in this repository in their relative folders. For development or running the application on your local machine, you have to run both the `machinery` and the `web` as described below. When running in production everything is shipped as only one artifact, read more about this at [Building for production](#building-for-production).
### UI
@@ -347,13 +356,13 @@ This will start a webserver and launches the web app on port `3000`.
![login-agent](./assets/img/agent-login.gif)
Once signed in you'll see the dashboard page showing up. After successfull configuration of your agent, you'll should see a live view and possible events recorded to disk.
Once signed in you'll see the dashboard page. After successfull configuration of your agent, you'll should see a live view and possible events recorded to disk.
![dashboard-agent](./assets/img/agent-dashboard.png)
### Machinery
The `machinery` is a **Golang** project which delivers two functions: it acts as the Kerberos Agent which is doing all the heavy lifting with camera processing and other kinds of logic, on the other hand it acts as a webserver (Rest API) that allows communication from the web (React) or any other custom application. The API is documented using `swagger`.
The `machinery` is a **Golang** project which delivers two functions: it acts as the Kerberos Agent which is doing all the heavy lifting with camera processing and other kinds of logic and on the other hand it acts as a webserver (Rest API) that allows communication from the web (React) or any other custom application. The API is documented using `swagger`.
You can simply run the `machinery` using following commands.
@@ -361,13 +370,13 @@ You can simply run the `machinery` using following commands.
cd machinery
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.
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 built in.
![VSCode desktop](./assets/img/vscode-desktop.png)
## Building from source
Running Kerberos Agent in production only require a single binary to run. Nevertheless, we have two parts, the `machinery` and the `web`, we merge them during build time. So this is what happens.
Running Kerberos Agent in production only requires a single binary to run. Nevertheless, we have two parts: the `machinery` and the `web`, we merge them during build time. So this is what happens.
### UI
@@ -378,7 +387,7 @@ To build the Kerberos Agent web app, you simply have to run the `build` command
### Machinery
Building the `machinery` is also super easy 🚀, by using `go build` you can create a single binary which ships it all; thank you Golang. After building you will endup with a binary called `main`, this is what contains everything you need to run Kerberos Agent.
Building the `machinery` is also super easy 🚀, by using `go build` you can create a single binary which ships it all; thank you Golang. After building you will end up with a binary called `main`, this is what contains everything you need to run Kerberos Agent.
Remember the build step of the `web` part, during build time we move the build directory to the `machinery` directory. Inside the `machinery` web server [we reference the](https://github.com/kerberos-io/agent/blob/master/machinery/src/routers/http/Server.go#L44) `build` directory. This makes it possible to just a have single web server that runs it all.
@@ -387,8 +396,8 @@ Remember the build step of the `web` part, during build time we move the build d
## Building for Docker
Inside the root of this `agent` repository, you will find a `Dockerfile`. This file contains the instructions for building and shipping **Kerberos Agent**. Important to note is that start from a prebuild base image, `kerberos/base:xxx`.
This base image contains already a couple of tools, such as Golang, FFmpeg and OpenCV. We do this for faster compilation times.
Inside the root of this `agent` repository, you will find a `Dockerfile`. This file contains the instructions for building and shipping a **Kerberos Agent**. Important to note is that you start from a prebuilt base image, `kerberos/base:xxx`.
This base image already contains a couple of tools, such as Golang, FFmpeg and OpenCV. We do this for faster compilation times.
By running the `docker build` command, you will create the Kerberos Agent Docker image. After building you can simply run the image as a Docker container.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 696 KiB

View File

@@ -36,8 +36,8 @@ You attach a volume to your container by leveraging the `-v` option. To mount yo
docker run -p 80:80 --name mycamera \
-v $(pwd)/agent/config:/home/agent/data/config \
-v $(pwd)/agent/recordings:/home/agent/data/recordings\
-d --restart=alwayskerberos/agent:latest
-v $(pwd)/agent/recordings:/home/agent/data/recordings \
-d --restart=always kerberos/agent:latest
### Override with environment variables

View File

@@ -1,35 +1,38 @@
version: "3.9"
x-common-variables: &common-variables
# Add variables here to add them to all agents
AGENT_HUB_KEY: "xxxxx" # The access key linked to your account in Kerberos Hub.
AGENT_HUB_PRIVATE_KEY: "xxxxx" # The secret access key linked to your account in Kerberos Hub.
# find full list of environment variables here: https://github.com/kerberos-io/agent#override-with-environment-variables
services:
kerberos-agent1:
image: "kerberos/agent:latest"
ports:
- "8081:80"
environment:
- AGENT_NAME=agent1
- AGENT_CAPTURE_IPCAMERA_RTSP=rtsp://x.x.x.x:554/Streaming/Channels/101
- AGENT_HUB_KEY=xxx
- AGENT_HUB_PRIVATE_KEY=xxx
- AGENT_CAPTURE_CONTINUOUS=true
- AGENT_CAPTURE_PRERECORDING=10
- AGENT_CAPTURE_POSTRECORDING=10
- AGENT_CAPTURE_MAXLENGTH=60
- AGENT_CAPTURE_PIXEL_CHANGE=150
# find full list of environment variables here: https://github.com/kerberos-io/agent#override-with-environment-variables
<<: *common-variables
AGENT_NAME: agent1
AGENT_CAPTURE_IPCAMERA_RTSP: rtsp://username:password@x.x.x.x/Streaming/Channels/101 # Hikvision camera RTSP url example
AGENT_KEY: "1"
kerberos-agent2:
image: "kerberos/agent:latest"
ports:
- "8082:80"
environment:
- AGENT_NAME=agent2
- AGENT_CAPTURE_IPCAMERA_RTSP=rtsp://x.x.x.x:554/Streaming/Channels/101
- AGENT_HUB_KEY=yyy
- AGENT_HUB_PRIVATE_KEY=yyy
<<: *common-variables
AGENT_NAME: agent2
AGENT_CAPTURE_IPCAMERA_RTSP: rtsp://username:password@x.x.x.x/channel1 # Linksys camera RTSP url example
AGENT_KEY: "2"
kerberos-agent3:
image: "kerberos/agent:latest"
ports:
- "8083:80"
environment:
- AGENT_NAME=agent3
- AGENT_CAPTURE_IPCAMERA_RTSP=rtsp://x.x.x.x:554/Streaming/Channels/101
- AGENT_HUB_KEY=zzz
- AGENT_HUB_PRIVATE_KEY=zzz
<<: *common-variables
AGENT_NAME: agent3
AGENT_CAPTURE_IPCAMERA_RTSP: rtsp://username:password@x.x.x.x/cam/realmonitor?channel=1&subtype=1 # Dahua camera RTSP url example
AGENT_KEY: "3"
networks:
default:
name: cluster-net
external: true

View File

@@ -16,7 +16,7 @@ spec:
spec:
containers:
- name: agent
image: kerberos/agent:latest
image: kerberos/agent:3.2.3
ports:
- containerPort: 80
protocol: TCP
@@ -50,4 +50,4 @@ spec:
- port: 80
targetPort: 80
selector:
app: agent
app: agent

View File

@@ -1,18 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "main.go",
"args": ["-action", "run"],
"envFile": "${workspaceFolder}/.env",
"buildFlags": "--tags dynamic",
},
]
}

View File

@@ -103,6 +103,7 @@
"mqtt_username": "",
"mqtt_password": "",
"stunuri": "stun:turn.kerberos.io:8443",
"turn_force": "false",
"turnuri": "turn:turn.kerberos.io:8443",
"turn_username": "username1",
"turn_password": "password1",
@@ -113,5 +114,7 @@
"hub_private_key": "",
"hub_site": "",
"condition_uri": "",
"encryption": {}
"encryption": {},
"realtimeprocessing": "false",
"realtimeprocessing_topic": ""
}

View File

@@ -1,5 +1,4 @@
// Package docs GENERATED BY SWAG; DO NOT EDIT
// This file was generated by swaggo/swag
// Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs
import "github.com/swaggo/swag"
@@ -388,7 +387,7 @@ const docTemplate = `{
"operationId": "snapshot-base64",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -403,7 +402,7 @@ const docTemplate = `{
"operationId": "snapshot-jpeg",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -476,7 +475,7 @@ const docTemplate = `{
"operationId": "config",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
},
@@ -500,7 +499,7 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -515,7 +514,7 @@ const docTemplate = `{
"operationId": "dashboard",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -530,7 +529,7 @@ const docTemplate = `{
"operationId": "days",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -590,7 +589,7 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -803,6 +802,9 @@ const docTemplate = `{
"description": "obsolete",
"type": "string"
},
"hub_encryption": {
"type": "string"
},
"hub_key": {
"type": "string"
},
@@ -839,6 +841,12 @@ const docTemplate = `{
"offline": {
"type": "string"
},
"realtimeprocessing": {
"type": "string"
},
"realtimeprocessing_topic": {
"type": "string"
},
"region": {
"$ref": "#/definitions/models.Region"
},
@@ -863,6 +871,9 @@ const docTemplate = `{
"timezone": {
"type": "string"
},
"turn_force": {
"type": "string"
},
"turn_password": {
"type": "string"
},
@@ -957,9 +968,18 @@ const docTemplate = `{
"rtsp": {
"type": "string"
},
"sub_fps": {
"type": "string"
},
"sub_height": {
"type": "integer"
},
"sub_rtsp": {
"type": "string"
},
"sub_width": {
"type": "integer"
},
"width": {
"type": "integer"
}
@@ -1166,6 +1186,8 @@ var SwaggerInfo = &swag.Spec{
Description: "This is the API for using and configure Kerberos Agent.",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {

View File

@@ -380,7 +380,7 @@
"operationId": "snapshot-base64",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -395,7 +395,7 @@
"operationId": "snapshot-jpeg",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -468,7 +468,7 @@
"operationId": "config",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
},
@@ -492,7 +492,7 @@
],
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -507,7 +507,7 @@
"operationId": "dashboard",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -522,7 +522,7 @@
"operationId": "days",
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -582,7 +582,7 @@
],
"responses": {
"200": {
"description": ""
"description": "OK"
}
}
}
@@ -795,6 +795,9 @@
"description": "obsolete",
"type": "string"
},
"hub_encryption": {
"type": "string"
},
"hub_key": {
"type": "string"
},
@@ -831,6 +834,12 @@
"offline": {
"type": "string"
},
"realtimeprocessing": {
"type": "string"
},
"realtimeprocessing_topic": {
"type": "string"
},
"region": {
"$ref": "#/definitions/models.Region"
},
@@ -855,6 +864,9 @@
"timezone": {
"type": "string"
},
"turn_force": {
"type": "string"
},
"turn_password": {
"type": "string"
},
@@ -949,9 +961,18 @@
"rtsp": {
"type": "string"
},
"sub_fps": {
"type": "string"
},
"sub_height": {
"type": "integer"
},
"sub_rtsp": {
"type": "string"
},
"sub_width": {
"type": "integer"
},
"width": {
"type": "integer"
}

View File

@@ -95,6 +95,8 @@ definitions:
heartbeaturi:
description: obsolete
type: string
hub_encryption:
type: string
hub_key:
type: string
hub_private_key:
@@ -119,6 +121,10 @@ definitions:
type: string
offline:
type: string
realtimeprocessing:
type: string
realtimeprocessing_topic:
type: string
region:
$ref: '#/definitions/models.Region'
remove_after_upload:
@@ -135,6 +141,8 @@ definitions:
type: array
timezone:
type: string
turn_force:
type: string
turn_password:
type: string
turn_username:
@@ -196,8 +204,14 @@ definitions:
type: string
rtsp:
type: string
sub_fps:
type: string
sub_height:
type: integer
sub_rtsp:
type: string
sub_width:
type: integer
width:
type: integer
type: object
@@ -564,7 +578,7 @@ paths:
operationId: snapshot-base64
responses:
"200":
description: ""
description: OK
summary: Get a snapshot from the camera in base64.
tags:
- camera
@@ -574,7 +588,7 @@ paths:
operationId: snapshot-jpeg
responses:
"200":
description: ""
description: OK
summary: Get a snapshot from the camera in jpeg format.
tags:
- camera
@@ -624,7 +638,7 @@ paths:
operationId: config
responses:
"200":
description: ""
description: OK
summary: Get the current configuration.
tags:
- config
@@ -640,7 +654,7 @@ paths:
$ref: '#/definitions/models.Config'
responses:
"200":
description: ""
description: OK
summary: Update the current configuration.
tags:
- config
@@ -650,7 +664,7 @@ paths:
operationId: dashboard
responses:
"200":
description: ""
description: OK
summary: Get all information showed on the dashboard.
tags:
- general
@@ -660,7 +674,7 @@ paths:
operationId: days
responses:
"200":
description: ""
description: OK
summary: Get all days stored in the recordings directory.
tags:
- general
@@ -698,7 +712,7 @@ paths:
$ref: '#/definitions/models.EventFilter'
responses:
"200":
description: ""
description: OK
summary: Get the latest recordings (events) from the recordings directory.
tags:
- general

View File

@@ -1,71 +1,71 @@
module github.com/kerberos-io/agent/machinery
go 1.20
//replace github.com/kerberos-io/joy4 v1.0.63 => ../../../../github.com/kerberos-io/joy4
//replace github.com/kerberos-io/onvif v0.0.10 => ../../../../github.com/kerberos-io/onvif
go 1.22.2
require (
github.com/InVisionApp/conjungo v1.1.0
github.com/appleboy/gin-jwt/v2 v2.9.1
github.com/bluenviron/gortsplib/v4 v4.6.1
github.com/bluenviron/mediacommon v1.5.1
github.com/appleboy/gin-jwt/v2 v2.10.0
github.com/bluenviron/gortsplib/v4 v4.11.1
github.com/bluenviron/mediacommon v1.13.1
github.com/cedricve/go-onvif v0.0.0-20200222191200-567e8ce298f6
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5
github.com/eclipse/paho.mqtt.golang v1.4.2
github.com/elastic/go-sysinfo v1.9.0
github.com/gin-contrib/cors v1.4.0
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2
github.com/gin-gonic/gin v1.9.1
github.com/eclipse/paho.mqtt.golang v1.5.0
github.com/elastic/go-sysinfo v1.14.2
github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/pprof v1.5.0
github.com/gin-gonic/contrib v0.0.0-20240508051311-c1c6bf0061b0
github.com/gin-gonic/gin v1.10.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang-jwt/jwt/v4 v4.4.3
github.com/golang-module/carbon/v2 v2.2.3
github.com/gorilla/websocket v1.5.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang-module/carbon/v2 v2.4.1
github.com/gorilla/websocket v1.5.3
github.com/kellydunn/golang-geo v0.7.0
github.com/kerberos-io/joy4 v1.0.64
github.com/kerberos-io/onvif v0.0.14
github.com/kerberos-io/onvif v0.0.16
github.com/minio/minio-go/v6 v6.0.57
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pion/rtp v1.8.3
github.com/pion/webrtc/v3 v3.1.50
github.com/sirupsen/logrus v1.9.0
github.com/swaggo/files v1.0.0
github.com/swaggo/gin-swagger v1.5.3
github.com/swaggo/swag v1.8.9
github.com/pion/rtp v1.8.9
github.com/pion/webrtc/v4 v4.0.1
github.com/sirupsen/logrus v1.9.3
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.4
github.com/tevino/abool v1.2.0
github.com/yapingcat/gomedia v0.0.0-20231203152327-9078d4068ce7
github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359
go.mongodb.org/mongo-driver v1.7.5
gopkg.in/DataDog/dd-trace-go.v1 v1.46.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
github.com/yapingcat/gomedia v0.0.0-20240906162731-17feea57090c
github.com/zaf/g711 v1.4.0
go.mongodb.org/mongo-driver v1.17.1
gopkg.in/DataDog/dd-trace-go.v1 v1.69.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 // indirect
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.42.0-rc.1 // indirect
github.com/DataDog/datadog-go v4.8.2+incompatible // indirect
github.com/DataDog/datadog-go/v5 v5.0.2 // indirect
github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork // indirect
github.com/DataDog/gostackparse v0.5.0 // indirect
github.com/DataDog/sketches-go v1.2.1 // indirect
github.com/DataDog/appsec-internal-go v1.8.0 // indirect
github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 // indirect
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 // indirect
github.com/DataDog/datadog-go/v5 v5.3.0 // indirect
github.com/DataDog/go-libddwaf/v3 v3.4.0 // indirect
github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect
github.com/DataDog/gostackparse v0.7.0 // indirect
github.com/DataDog/sketches-go v1.4.5 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beevik/etree v1.2.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/bytedance/sonic v1.12.2 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect
github.com/ebitengine/purego v0.6.0-alpha.5 // indirect
github.com/elastic/go-windows v1.0.0 // indirect
github.com/elgs/gostrgen v0.0.0-20220325073726-0c3e00d082f6 // indirect
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae // indirect
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
@@ -73,80 +73,83 @@ require (
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/go-playground/validator/v10 v10.22.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20210423192551-a2663126120b // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/icholy/digest v0.1.23 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/juju/errors v1.0.0 // indirect
github.com/klauspost/compress v1.17.1 // indirect
github.com/klauspost/cpuid v1.2.3 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kylelemons/go-gypsy v1.0.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.2 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/md5-simd v1.1.0 // indirect
github.com/minio/sha256-simd v0.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/gomega v1.27.4 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/philhofer/fwd v1.1.1 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.1.5 // indirect
github.com/pion/ice/v2 v2.2.12 // indirect
github.com/pion/interceptor v0.1.11 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/outcaste-io/ristretto v0.2.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
github.com/pion/datachannel v1.5.9 // indirect
github.com/pion/dtls/v3 v3.0.3 // indirect
github.com/pion/ice/v4 v4.0.2 // indirect
github.com/pion/interceptor v0.1.37 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect
github.com/pion/mdns/v2 v2.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.12 // indirect
github.com/pion/sctp v1.8.5 // indirect
github.com/pion/sdp/v3 v3.0.6 // indirect
github.com/pion/srtp/v2 v2.0.10 // indirect
github.com/pion/stun v0.3.5 // indirect
github.com/pion/transport v0.14.1 // indirect
github.com/pion/turn/v2 v2.0.8 // indirect
github.com/pion/udp v0.1.1 // indirect
github.com/pion/rtcp v1.2.14 // indirect
github.com/pion/sctp v1.8.33 // indirect
github.com/pion/sdp/v3 v3.0.9 // indirect
github.com/pion/srtp/v3 v3.0.4 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
github.com/pion/turn/v4 v4.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tinylib/msgp v1.1.6 // indirect
github.com/tinylib/msgp v1.2.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/wlynxg/anet v0.0.3 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/ziutek/mymysql v1.5.4 // indirect
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/tools v0.7.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/grpc v1.32.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/arch v0.9.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.9.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.42.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect
inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect
)

View File

@@ -31,57 +31,58 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 h1:3nVO1nQyh64IUY6BPZUpMYMZ738Pu+LsMt3E0eqqIYw=
github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583/go.mod h1:EP9f4GqaDJyP1F5jTNMtzdIpw3JpNs3rMSJOnYywCiw=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.42.0-rc.1 h1:Rmz52Xlc5k3WzAHzD0SCH4USCzyti7EbK4HtrHys3ME=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.42.0-rc.1/go.mod h1:VVMDDibJxYEkwcLdZBT2g8EHKpbMT4JdOhRbQ9GdjbM=
github.com/DataDog/datadog-go v4.8.2+incompatible h1:qbcKSx29aBLD+5QLvlQZlGmRMF/FfGqFLFev/1TDzRo=
github.com/DataDog/datadog-go v4.8.2+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go/v5 v5.0.2 h1:UFtEe7662/Qojxkw1d6SboAeA0CPI3naKhVASwFn+04=
github.com/DataDog/datadog-go/v5 v5.0.2/go.mod h1:ZI9JFB4ewXbw1sBnF4sxsR2k1H3xjV+PUAOUsHvKpcU=
github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork h1:yBq5PrAtrM4yVeSzQ+bn050+Ysp++RKF1QmtkL4VqvU=
github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork/go.mod h1:yA5JwkZsHTLuqq3zaRgUQf35DfDkpOZqgtBqHKpwrBs=
github.com/DataDog/gostackparse v0.5.0 h1:jb72P6GFHPHz2W0onsN51cS3FkaMDcjb0QzgxxA4gDk=
github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
github.com/DataDog/sketches-go v1.2.1 h1:qTBzWLnZ3kM2kw39ymh6rMcnN+5VULwFs++lEYUUsro=
github.com/DataDog/sketches-go v1.2.1/go.mod h1:1xYmPLY1So10AwxV6MJV0J53XVH+WL9Ad1KetxVivVI=
github.com/DataDog/appsec-internal-go v1.8.0 h1:1Tfn3LEogntRqZtf88twSApOCAAO3V+NILYhuQIo4J4=
github.com/DataDog/appsec-internal-go v1.8.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g=
github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8=
github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 h1:LplNAmMgZvGU7kKA0+4c1xWOjz828xweW5TCi8Mw9Q0=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0/go.mod h1:4Vo3SJ24uzfKHUHLoFa8t8o+LH+7TCQ7sPcZDtOpSP4=
github.com/DataDog/datadog-go/v5 v5.3.0 h1:2q2qjFOb3RwAZNU+ez27ZVDwErJv5/VpbBPprz7Z+s8=
github.com/DataDog/datadog-go/v5 v5.3.0/go.mod h1:XRDJk1pTc00gm+ZDiBKsjh7oOOtJfYfglVCmFb8C2+Q=
github.com/DataDog/go-libddwaf/v3 v3.4.0 h1:NJ2W2vhYaOm1OWr1LJCbdgp7ezG/XLJcQKBmjFwhSuM=
github.com/DataDog/go-libddwaf/v3 v3.4.0/go.mod h1:n98d9nZ1gzenRSk53wz8l6d34ikxS+hs62A31Fqmyi4=
github.com/DataDog/go-tuf v1.1.0-0.5.2 h1:4CagiIekonLSfL8GMHRHcHudo1fQnxELS9g4tiAupQ4=
github.com/DataDog/go-tuf v1.1.0-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0=
github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4=
github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
github.com/DataDog/sketches-go v1.4.5 h1:ki7VfeNz7IcNafq7yI/j5U/YCkO3LJiMDtXz9OMQbyE=
github.com/DataDog/sketches-go v1.4.5/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt8jHOBWWrSOg=
github.com/InVisionApp/conjungo v1.1.0 h1:NMPwvjK0i7UujnGnpbvAscruuroeYYVR55OAgBmM6oc=
github.com/InVisionApp/conjungo v1.1.0/go.mod h1:86uJs2j/N0qcjh0ORLQDw1bB5kPFS/CoprqySSyp8dc=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
github.com/appleboy/gin-jwt/v2 v2.9.1 h1:l29et8iLW6omcHltsOP6LLk4s3v4g2FbFs0koxGWVZs=
github.com/appleboy/gin-jwt/v2 v2.9.1/go.mod h1:jwcPZJ92uoC9nOUTOKWoN/f6JZOgMSKlFSHw5/FrRUk=
github.com/appleboy/gin-jwt/v2 v2.10.0 h1:vOlGSly8oIGQiT8AcEh1nYMLYI1K9YvsZNVWM612xN0=
github.com/appleboy/gin-jwt/v2 v2.10.0/go.mod h1:DvCh3V1Ma32/7kAsAHYQVyjsQMwG+wMXGpyCYLfHOJU=
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw=
github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc=
github.com/bluenviron/gortsplib/v4 v4.6.1 h1:+xI/hrNM/KX3qenqzKIG0MG8z+IHg0xu8OEoMfDZ+wg=
github.com/bluenviron/gortsplib/v4 v4.6.1/go.mod h1:dN1YjyPNMfy/NwC17Ga6MiIMiUoQfg5GL7LGsVHa0Jo=
github.com/bluenviron/mediacommon v1.5.1 h1:yYVF+ebqZOJh8yH+EeuPcAtTmWR66BqbJGmStxkScoI=
github.com/bluenviron/mediacommon v1.5.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bluenviron/gortsplib/v4 v4.11.1 h1:yq9mCVydwRUjyc4dzGrNs7/R8DvErbZ7fzIzBPlwVl8=
github.com/bluenviron/gortsplib/v4 v4.11.1/go.mod h1:yVEgmJnwHGo3Po7dWW0aVjZGCUmOULEZp9i1IMtWqao=
github.com/bluenviron/mediacommon v1.13.1 h1:agxDtkooknxSxOO/oOpB+tEW48OLMqty1PDMC3x2n4E=
github.com/bluenviron/mediacommon v1.13.1/go.mod h1:HDyW2CzjvhYJXtdxstdFPio3G0qSocPhqkhUt/qffec=
github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg=
github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cedricve/go-onvif v0.0.0-20200222191200-567e8ce298f6 h1:bzFZYgZD5vf4PWaa2GjOh90HG88uKi2a+B6VnQcDlCA=
github.com/cedricve/go-onvif v0.0.0-20200222191200-567e8ce298f6/go.mod h1:nBrjN2nMHendp0Cvb/6GaJ1v92Qv/kzqxWtNBnKJEK0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -90,56 +91,58 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 h1:FT+t0UEDykcor4y3dMVKXIiWJETBpRgERYTGlmMd7HU=
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5/go.mod h1:rSS3kM9XMzSQ6pw91Qgd6yB5jdt70N4OdtrAf74As5M=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/eclipse/paho.mqtt.golang v1.4.2 h1:66wOzfUHSSI1zamx7jR6yMEI5EuHnT1G6rNA5PM12m4=
github.com/eclipse/paho.mqtt.golang v1.4.2/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
github.com/elastic/go-sysinfo v1.9.0 h1:usICqY/Nw4Mpn9f4LdtpFrKxXroJDe81GaxxUlCckIo=
github.com/elastic/go-sysinfo v1.9.0/go.mod h1:eBD1wEGVaRnRLGecc9iG1z8eOv5HnEdz9+nWd8UAxcE=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds=
github.com/ebitengine/purego v0.6.0-alpha.5 h1:EYID3JOAdmQ4SNZYJHu9V6IqOeRQDBYxqKAg9PyoHFY=
github.com/ebitengine/purego v0.6.0-alpha.5/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
github.com/elastic/go-sysinfo v1.14.2 h1:DeIy+pVfdRsd08Nx2Xjh+dUS+jrEEI7LGc29U/BKVWo=
github.com/elastic/go-sysinfo v1.14.2/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk=
github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
github.com/elgs/gostrgen v0.0.0-20220325073726-0c3e00d082f6 h1:x9TA+vnGEyqmWY+eA9HfgxNRkOQqwiEpFE9IPXSGuEA=
github.com/elgs/gostrgen v0.0.0-20220325073726-0c3e00d082f6/go.mod h1:wruC5r2gHdr/JIUs5Rr1V45YtsAzKXZxAnn/5rPC97g=
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae h1:3KvK2DmA7TxQ6PZ2f0rWbdqjgJhRcqgbY70bBeE4clI=
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae/go.mod h1:wruC5r2gHdr/JIUs5Rr1V45YtsAzKXZxAnn/5rPC97g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/flynn/go-docopt v0.0.0-20140912013429-f6dd2ebbb31e/go.mod h1:HyVoz1Mz5Co8TFO8EupIdlcpwShBmY98dkT2xeHkvEI=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90=
github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU=
github.com/gin-contrib/pprof v1.5.0/go.mod h1:GqFL6LerKoCQ/RSWnkYczkTJ+tOAUVN/8sbnEtaqOKs=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2 h1:dyuNlYlG1faymw39NdJddnzJICy6587tiGSVioWhYoE=
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gin-gonic/contrib v0.0.0-20240508051311-c1c6bf0061b0 h1:EUFmvQ8ffefnSAmaUZd9HZYZSw9w/bFjp3FiNaJ5WmE=
github.com/gin-gonic/contrib v0.0.0-20240508051311-c1c6bf0061b0/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -153,32 +156,22 @@ github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-module/carbon/v2 v2.2.3 h1:WvGIc5+qzq9drNzH+Gnjh1TZ0JgDY/IA+m2Dvk7Qm4Q=
github.com/golang-module/carbon/v2 v2.2.3/go.mod h1:LdzRApgmDT/wt0eNT8MEJbHfJdSqCtT46uZhfF30dqI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-module/carbon/v2 v2.4.1 h1:cYUD8T+rHeX+qIybGYpnJ8I90F10dvyEF67VNOO+zZM=
github.com/golang-module/carbon/v2 v2.4.1/go.mod h1:1jP9AZ4k2+lmfgY/wZgmtsN52VcHC5YuPM6varKDTkM=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -190,6 +183,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -204,10 +198,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -219,10 +211,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -236,28 +227,32 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210423192551-a2663126120b h1:l2YRhr+YLzmSp7KJMswRVk/lO5SwoFIcCLzJsVj+YPc=
github.com/google/pprof v0.0.0-20210423192551-a2663126120b/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/icholy/digest v0.1.23 h1:4hX2pIloP0aDx7RJW0JewhPPy3R8kU+vWKdxPsCCGtY=
github.com/icholy/digest v0.1.23/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -267,24 +262,27 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM=
github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kellydunn/golang-geo v0.7.0 h1:A5j0/BvNgGwY6Yb6inXQxzYwlPHc6WVZR+MrarZYNNg=
github.com/kellydunn/golang-geo v0.7.0/go.mod h1:YYlQPJ+DPEzrHx8kT3oPHC/NjyvCCXE+IuKGKdrjrcU=
github.com/kerberos-io/joy4 v1.0.64 h1:gTUSotHSOhp9mNqEecgq88tQHvpj7TjmrvPUsPm0idg=
github.com/kerberos-io/joy4 v1.0.64/go.mod h1:nZp4AjvKvTOXRrmDyAIOw+Da+JA5OcSo/JundGfOlFU=
github.com/kerberos-io/onvif v0.0.14 h1:ZcpsIAFbuR/mEuTmMnyHM2sLX7OsnQ5sCjmhsgL33VI=
github.com/kerberos-io/onvif v0.0.14/go.mod h1:NAsn+VuMB/hvrm40xULWyiLJ/ArB5nAecX5hvDo5gcA=
github.com/kerberos-io/onvif v0.0.16 h1:fSiyc5ja6Q6ux6Jscvv4TVDPeK8O9x8WT1fG7YsbC8Q=
github.com/kerberos-io/onvif v0.0.16/go.mod h1:P1kUcCfeotJSlL1jwGseH6NSnCwWiuJLl3gAzafnLbA=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g=
github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -293,142 +291,126 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/go-gypsy v1.0.0 h1:7/wQ7A3UL1bnqRMnZ6T8cwCOArfZCxFmb1iTxaOOo1s=
github.com/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/9Tw=
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c=
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
github.com/pion/ice/v2 v2.2.12 h1:n3M3lUMKQM5IoofhJo73D3qVla+mJN2nVvbSPq32Nig=
github.com/pion/ice/v2 v2.2.12/go.mod h1:z2KXVFyRkmjetRlaVRgjO9U3ShKwzhlUylvxKfHfd5A=
github.com/pion/interceptor v0.1.11 h1:00U6OlqxA3FFB50HSg25J/8cWi7P6FbSzw4eFn24Bvs=
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0=
github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 h1:jYi87L8j62qkXzaYHAQAhEapgukhenIMZRBKTNRLHJ4=
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA=
github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE=
github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM=
github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU=
github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s=
github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg=
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtcp v1.2.12 h1:bKWiX93XKgDZENEXCijvHRU/wRifm6JV5DGcH6twtSM=
github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8=
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/sctp v1.8.5 h1:JCc25nghnXWOlSn3OVtEnA9PjQ2JsxQbG+CXZ1UkJKQ=
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp/v2 v2.0.10 h1:b8ZvEuI+mrL8hbr/f1YiJFB34UMrOac3R3N1yq2UN0w=
github.com/pion/srtp/v2 v2.0.10/go.mod h1:XEeSWaK9PfuMs7zxXyiN252AHPbH12NX5q/CFDWtUuA=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.50 h1:wLMo1+re4WMZ9Kun9qcGcY+XoHkE3i0CXrrc0sjhVCk=
github.com/pion/webrtc/v3 v3.1.50/go.mod h1:y9n09weIXB+sjb9mi0GBBewNxo4TKUQm5qdtT5v3/X4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=
github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM=
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
github.com/pion/webrtc/v4 v4.0.1 h1:6Unwc6JzoTsjxetcAIoWH81RUM4K5dBc1BbJGcF9WVE=
github.com/pion/webrtc/v4 v4.0.1/go.mod h1:SfNn8CcFxR6OUVjLXVslAQ3a3994JhyE3Hw1jAuqEto=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA=
github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 h1:4+LEVOB87y175cLJC/mbsgKmoDOjrBldtXvioEy96WY=
github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3/go.mod h1:vl5+MqJ1nBINuSsUI2mGgH79UweUT/B5Fy8857PqyyI=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/secure-systems-lab/go-securesystemslib v0.3.1/go.mod h1:o8hhjkbNl2gOamKUA/eNW3xUrntHT9L4W89W1nfj43U=
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg=
github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -438,88 +420,73 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4=
github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc=
github.com/swaggo/gin-swagger v1.5.3 h1:8mWmHLolIbrhJJTflsaFoZzRBYVmEE7JZGIq08EiC0Q=
github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89Yp4uA50HpI=
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA=
github.com/swaggo/swag v1.8.9/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw=
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tinylib/msgp v1.2.1 h1:6ypy2qcCznxpP4hpORzhtXyTqrBs7cfM9MCCWY8zsmU=
github.com/tinylib/msgp v1.2.1/go.mod h1:2vIGs3lcUo8izAATNobrCHevYZC/LMsJtw4JPiYPHro=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg=
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/yapingcat/gomedia v0.0.0-20231203152327-9078d4068ce7 h1:CDxRmG9/kGMMHbKuJezAM7Bp40P7EH2MqBn3qqf0bok=
github.com/yapingcat/gomedia v0.0.0-20231203152327-9078d4068ce7/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/yapingcat/gomedia v0.0.0-20240906162731-17feea57090c h1:xA2TJS9Hu/ivzaZIrDcwvpJ3Fnpsk5fDOJ4iSnL6J0w=
github.com/yapingcat/gomedia v0.0.0-20240906162731-17feea57090c/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359 h1:P9yeMx2iNJxJqXEwLtMjSwWcD2a0AlFmFByeosMZhLM=
github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359/go.mod h1:ySLGJD8AQluMQuu5JDvfJrwsBra+8iX1jFsKS8KfB2I=
github.com/zaf/g711 v1.4.0 h1:XZYkjjiAg9QTBnHqEg37m2I9q3IIDv5JRYXs2N8ma7c=
github.com/zaf/g711 v1.4.0/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k=
golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -552,10 +519,10 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -574,42 +541,28 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 h1:Lm4OryKCca1vehdsWogr9N4t7NfZxLbJoc/H0w4K4S4=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs=
golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -618,13 +571,12 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -634,11 +586,8 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -652,57 +601,42 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -713,7 +647,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@@ -745,18 +678,16 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -778,8 +709,9 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -808,7 +740,6 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -822,8 +753,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg=
google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -836,40 +767,35 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/DataDog/dd-trace-go.v1 v1.46.0 h1:h/SbNfGfDMhBkB+/zzCWKPOlLcdd0Fc+QBAnZm009XM=
gopkg.in/DataDog/dd-trace-go.v1 v1.46.0/go.mod h1:kaa8caaECrtY0V/MUtPQAh1lx/euFzPJwrY1taTx3O4=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/DataDog/dd-trace-go.v1 v1.69.0 h1:zSY6DDsFRMQDNQYKWCv/AEwJXoPpDf1FfMyw7I1B7M8=
gopkg.in/DataDog/dd-trace-go.v1 v1.69.0/go.mod h1:U9AOeBHNAL95JXcd/SPf4a7O5GNeF/yD13sJtli/yaU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -879,9 +805,27 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU=
inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw=
modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -19,7 +19,7 @@ import (
"gopkg.in/DataDog/dd-trace-go.v1/profiler"
)
var VERSION = "3.0.0"
var VERSION = utils.VERSION
func main() {
// You might be interested in debugging the agent.

View File

@@ -63,7 +63,12 @@ type Golibrtsp struct {
AudioG711Index int8
AudioG711Media *description.Media
AudioG711Forma *format.G711
AudioG711Decoder *rtpsimpleaudio.Decoder
AudioG711Decoder *rtplpcm.Decoder
AudioOpusIndex int8
AudioOpusMedia *description.Media
AudioOpusForma *format.Opus
AudioOpusDecoder *rtpsimpleaudio.Decoder
HasBackChannel bool
AudioG711IndexBackChannel int8
@@ -124,41 +129,53 @@ func (g *Golibrtsp) Connect(ctx context.Context) (err error) {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(H264): " + err.Error())
} else {
// Get SPS from the SDP
// Get SPS and PPS from the SDP
// Calculate the width and height of the video
var sps h264.SPS
err = sps.Unmarshal(formaH264.SPS)
if err != nil {
log.Log.Debug("capture.golibrtsp.Connect(H264): " + err.Error())
return
errSPS := sps.Unmarshal(formaH264.SPS)
// It might be that the SPS is not available yet, so we'll proceed,
// but try to fetch it later on.
if errSPS != nil {
log.Log.Debug("capture.golibrtsp.Connect(H264): " + errSPS.Error())
g.Streams = append(g.Streams, packets.Stream{
Name: formaH264.Codec(),
IsVideo: true,
IsAudio: false,
SPS: []byte{},
PPS: []byte{},
Width: 0,
Height: 0,
FPS: 0,
IsBackChannel: false,
})
} else {
g.Streams = append(g.Streams, packets.Stream{
Name: formaH264.Codec(),
IsVideo: true,
IsAudio: false,
SPS: formaH264.SPS,
PPS: formaH264.PPS,
Width: sps.Width(),
Height: sps.Height(),
FPS: sps.FPS(),
IsBackChannel: false,
})
}
g.Streams = append(g.Streams, packets.Stream{
Name: formaH264.Codec(),
IsVideo: true,
IsAudio: false,
SPS: formaH264.SPS,
PPS: formaH264.PPS,
Width: sps.Width(),
Height: sps.Height(),
FPS: sps.FPS(),
IsBackChannel: false,
})
// Set the index for the video
g.VideoH264Index = int8(len(g.Streams)) - 1
// setup RTP/H264 -> H264 decoder
rtpDec, err := formaH264.CreateDecoder()
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(H264): " + err.Error())
}
g.VideoH264Decoder = rtpDec
// setup H264 -> raw frames decoder
frameDec, err := newDecoder("H264")
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(H264): " + err.Error())
}
g.VideoH264FrameDecoder = frameDec
}
@@ -206,14 +223,14 @@ func (g *Golibrtsp) Connect(ctx context.Context) (err error) {
// setup RTP/H265 -> H265 decoder
rtpDec, err := formaH265.CreateDecoder()
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(H265): " + err.Error())
}
g.VideoH265Decoder = rtpDec
// setup H265 -> raw frames decoder
frameDec, err := newDecoder("H265")
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(H265): " + err.Error())
}
g.VideoH265FrameDecoder = frameDec
}
@@ -254,6 +271,41 @@ func (g *Golibrtsp) Connect(ctx context.Context) (err error) {
}
}
// Look for audio stream.
// find the Opus media and format
audioFormaOpus, audioMediOpus := FindOPUS(desc, false)
g.AudioOpusMedia = audioMediOpus
g.AudioOpusForma = audioFormaOpus
if audioMediOpus == nil {
log.Log.Debug("capture.golibrtsp.Connect(Opus): " + "audio media not found")
} else {
// setup a audio media
_, err = g.Client.Setup(desc.BaseURL, audioMediOpus, 0, 0)
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(Opus): " + err.Error())
} else {
// create decoder
audiortpDec, err := audioFormaOpus.CreateDecoder()
if err != nil {
// Something went wrong .. Do something
log.Log.Error("capture.golibrtsp.Connect(Opus): " + err.Error())
} else {
g.AudioOpusDecoder = audiortpDec
g.Streams = append(g.Streams, packets.Stream{
Name: "OPUS",
IsVideo: false,
IsAudio: true,
IsBackChannel: false,
})
// Set the index for the audio
g.AudioOpusIndex = int8(len(g.Streams)) - 1
}
}
}
// Look for audio stream.
// find the AAC media and format
audioFormaMPEG4, audioMediMPEG4 := FindMPEG4Audio(desc, false)
@@ -357,8 +409,9 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
// called when a MULAW audio RTP packet arrives
if g.AudioG711Media != nil && g.AudioG711Forma != nil {
g.Client.OnPacketRTP(g.AudioG711Media, g.AudioG711Forma, func(rtppkt *rtp.Packet) {
// decode timestamp
pts, ok := g.Client.PacketPTS(g.AudioG711Media, rtppkt)
// decode timestamp
pts2, ok := g.Client.PacketPTS2(g.AudioG711Media, rtppkt)
if !ok {
log.Log.Debug("capture.golibrtsp.Start(): " + "unable to get PTS")
return
@@ -375,8 +428,9 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
IsKeyFrame: false,
Packet: rtppkt,
Data: op,
Time: pts,
CompositionTime: pts,
Time: pts2,
TimeLegacy: pts,
CompositionTime: pts2,
Idx: g.AudioG711Index,
IsVideo: false,
IsAudio: true,
@@ -391,6 +445,7 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
g.Client.OnPacketRTP(g.AudioMPEG4Media, g.AudioMPEG4Forma, func(rtppkt *rtp.Packet) {
// decode timestamp
pts, ok := g.Client.PacketPTS(g.AudioMPEG4Media, rtppkt)
pts2, ok := g.Client.PacketPTS2(g.AudioMPEG4Media, rtppkt)
if !ok {
log.Log.Error("capture.golibrtsp.Start(): " + "unable to get PTS")
return
@@ -414,8 +469,9 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
IsKeyFrame: false,
Packet: rtppkt,
Data: enc,
Time: pts,
CompositionTime: pts,
Time: pts2,
TimeLegacy: pts,
CompositionTime: pts2,
Idx: g.AudioG711Index,
IsVideo: false,
IsAudio: true,
@@ -428,6 +484,9 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
// called when a video RTP packet arrives for H264
var filteredAU [][]byte
if g.VideoH264Media != nil && g.VideoH264Forma != nil {
dtsExtractor := h264.NewDTSExtractor2()
g.Client.OnPacketRTP(g.VideoH264Media, g.VideoH264Forma, func(rtppkt *rtp.Packet) {
// This will check if we need to stop the thread,
@@ -442,6 +501,7 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
// decode timestamp
pts, ok := g.Client.PacketPTS(g.VideoH264Media, rtppkt)
pts2, ok := g.Client.PacketPTS2(g.VideoH264Media, rtppkt)
if !ok {
log.Log.Debug("capture.golibrtsp.Start(): " + "unable to get PTS")
return
@@ -468,6 +528,7 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
// Check if we have a keyframe.
nonIDRPresent := false
idrPresent := false
for _, nalu := range au {
typ := h264.NALUType(nalu[0] & 0x1F)
switch typ {
@@ -477,6 +538,32 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
idrPresent = true
case h264.NALUTypeNonIDR:
nonIDRPresent = true
case h264.NALUTypeSPS:
// Read out sps
var sps h264.SPS
errSPS := sps.Unmarshal(nalu)
if errSPS == nil {
// Get width
g.Streams[g.VideoH264Index].Width = sps.Width()
if streamType == "main" {
configuration.Config.Capture.IPCamera.Width = sps.Width()
} else if streamType == "sub" {
configuration.Config.Capture.IPCamera.SubWidth = sps.Width()
}
// Get height
g.Streams[g.VideoH264Index].Height = sps.Height()
if streamType == "main" {
configuration.Config.Capture.IPCamera.Height = sps.Height()
} else if streamType == "sub" {
configuration.Config.Capture.IPCamera.SubHeight = sps.Height()
}
// Get FPS
g.Streams[g.VideoH264Index].FPS = sps.FPS()
g.VideoH264Forma.SPS = nalu
}
case h264.NALUTypePPS:
// Read out pps
g.VideoH264Forma.PPS = nalu
}
filteredAU = append(filteredAU, nalu)
}
@@ -492,12 +579,20 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
return
}
// Extract DTS from RTP packets
dts2, err := dtsExtractor.Extract(filteredAU, pts2)
if err != nil {
log.Log.Error("capture.golibrtsp.Start(): " + err.Error())
return
}
pkt := packets.Packet{
IsKeyFrame: idrPresent,
Packet: rtppkt,
Data: enc,
Time: pts,
CompositionTime: pts,
Time: pts2,
TimeLegacy: pts,
CompositionTime: dts2,
Idx: g.VideoH264Index,
IsVideo: true,
IsAudio: false,
@@ -560,6 +655,7 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
// decode timestamp
pts, ok := g.Client.PacketPTS(g.VideoH265Media, rtppkt)
pts2, ok := g.Client.PacketPTS2(g.VideoH265Media, rtppkt)
if !ok {
log.Log.Debug("capture.golibrtsp.Start(): " + "unable to get PTS")
return
@@ -623,8 +719,9 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
IsKeyFrame: isRandomAccess,
Packet: rtppkt,
Data: enc,
Time: pts,
CompositionTime: pts,
Time: pts2,
TimeLegacy: pts,
CompositionTime: pts2,
Idx: g.VideoH265Index,
IsVideo: true,
IsAudio: false,
@@ -948,6 +1045,21 @@ func FindPCMU(desc *description.Session, isBackChannel bool) (*format.G711, *des
return nil, nil
}
func FindOPUS(desc *description.Session, isBackChannel bool) (*format.Opus, *description.Media) {
for _, media := range desc.Medias {
if media.IsBackChannel == isBackChannel {
for _, forma := range media.Formats {
if opus, ok := forma.(*format.Opus); ok {
if opus.ChannelCount > 0 {
return opus, media
}
}
}
}
}
return nil, nil
}
func FindMPEG4Audio(desc *description.Session, isBackChannel bool) (*format.MPEG4Audio, *description.Media) {
for _, media := range desc.Medias {
if media.IsBackChannel == isBackChannel {

View File

@@ -71,6 +71,10 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
startRecording := now
timestamp := now
if config.FriendlyName != "" {
config.Name = config.FriendlyName
}
// For continuous and motion based recording we will use a single file.
var file *os.File
@@ -116,7 +120,7 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
nextPkt.IsKeyFrame && (timestamp+recordingPeriod-now <= 0 || now-startRecording >= maxRecordingPeriod) {
// Write the last packet
ttime := convertPTS(pkt.Time)
ttime := convertPTS(pkt.TimeLegacy)
if pkt.IsVideo {
if err := myMuxer.Write(videoTrack, pkt.Data, ttime, ttime); err != nil {
log.Log.Error("capture.main.HandleRecordStream(continuous): " + err.Error())
@@ -223,10 +227,14 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
//cws = newCacheWriterSeeker(4096)
myMuxer, _ = mp4.CreateMp4Muxer(file)
// We choose between H264 and H265
width := configuration.Config.Capture.IPCamera.Width
height := configuration.Config.Capture.IPCamera.Height
widthOption := mp4.WithVideoWidth(uint32(width))
heightOption := mp4.WithVideoHeight(uint32(height))
if pkt.Codec == "H264" {
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H264)
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H264, widthOption, heightOption)
} else if pkt.Codec == "H265" {
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H265)
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H265, widthOption, heightOption)
}
// For an MP4 container, AAC is the only audio codec supported.
audioTrack = myMuxer.AddAudioTrack(mp4.MP4_CODEC_AAC)
@@ -234,7 +242,7 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
log.Log.Error("capture.main.HandleRecordStream(continuous): " + err.Error())
}
ttime := convertPTS(pkt.Time)
ttime := convertPTS(pkt.TimeLegacy)
if pkt.IsVideo {
if err := myMuxer.Write(videoTrack, pkt.Data, ttime, ttime); err != nil {
log.Log.Error("capture.main.HandleRecordStream(continuous): " + err.Error())
@@ -253,7 +261,7 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
recordingStatus = "started"
} else if start {
ttime := convertPTS(pkt.Time)
ttime := convertPTS(pkt.TimeLegacy)
if pkt.IsVideo {
if err := myMuxer.Write(videoTrack, pkt.Data, ttime, ttime); err != nil {
log.Log.Error("capture.main.HandleRecordStream(continuous): " + err.Error())
@@ -329,7 +337,7 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
log.Log.Info("capture.main.HandleRecordStream(motiondetection): Start motion based recording ")
var lastDuration time.Duration
var lastDuration int64
var lastRecordingTime int64
//var cws *cacheWriterSeeker
@@ -386,10 +394,14 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
// Check which video codec we need to use.
videoSteams, _ := rtspClient.GetVideoStreams()
for _, stream := range videoSteams {
width := configuration.Config.Capture.IPCamera.Width
height := configuration.Config.Capture.IPCamera.Height
widthOption := mp4.WithVideoWidth(uint32(width))
heightOption := mp4.WithVideoHeight(uint32(height))
if stream.Name == "H264" {
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H264)
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H264, widthOption, heightOption)
} else if stream.Name == "H265" {
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H265)
videoTrack = myMuxer.AddVideoTrack(mp4.MP4_CODEC_H265, widthOption, heightOption)
}
}
// For an MP4 container, AAC is the only audio codec supported.
@@ -432,8 +444,7 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
start = true
}
if start {
ttime := convertPTS(pkt.Time)
ttime := convertPTS(pkt.TimeLegacy)
if pkt.IsVideo {
if err := myMuxer.Write(videoTrack, pkt.Data, ttime, ttime); err != nil {
log.Log.Error("capture.main.HandleRecordStream(motiondetection): " + err.Error())
@@ -611,7 +622,9 @@ func Base64Image(captureDevice *Capture, communication *models.Communication) st
// We'll try to have a keyframe, if not we'll return an empty string.
var encodedImage string
for {
// Try for 3 times in a row.
count := 0
for count < 3 {
if queue != nil && cursor != nil && rtspClient != nil {
pkt, err := cursor.ReadPacket()
if err == nil {
@@ -624,8 +637,10 @@ func Base64Image(captureDevice *Capture, communication *models.Communication) st
bytes, _ := utils.ImageToBytes(&img)
encodedImage = base64.StdEncoding.EncodeToString(bytes)
break
} else {
count++
continue
}
break
}
} else {
break
@@ -652,15 +667,22 @@ func JpegImage(captureDevice *Capture, communication *models.Communication) imag
// We'll try to have a keyframe, if not we'll return an empty string.
var image image.YCbCr
for {
// Try for 3 times in a row.
count := 0
for count < 3 {
if queue != nil && cursor != nil && rtspClient != nil {
pkt, err := cursor.ReadPacket()
if err == nil {
if !pkt.IsKeyFrame {
continue
}
image, _ = (*rtspClient).DecodePacket(pkt)
break
image, err = (*rtspClient).DecodePacket(pkt)
if err != nil {
count++
continue
} else {
break
}
}
} else {
break
@@ -672,3 +694,7 @@ func JpegImage(captureDevice *Capture, communication *models.Communication) imag
func convertPTS(v time.Duration) uint64 {
return uint64(v.Milliseconds())
}
func convertPTS2(v int64) uint64 {
return uint64(v) / 100
}

View File

@@ -229,15 +229,17 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models.
} else {
client = &http.Client{}
}
config := configuration.Config
// Get a pull point address
var pullPointAddress string
if config.Capture.IPCamera.ONVIFXAddr != "" {
kerberosAgentVersion := utils.VERSION
// Create a loop pull point address, which we will use to retrieve async events
// As you'll read below camera manufactures are having different implementations of events.
var pullPointAddressLoopState string
if configuration.Config.Capture.IPCamera.ONVIFXAddr != "" {
cameraConfiguration := configuration.Config.Capture.IPCamera
device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil {
pullPointAddress, err = onvif.CreatePullPointSubscription(device)
if err != nil {
pullPointAddressLoopState, err = onvif.CreatePullPointSubscription(device)
if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error())
}
@@ -251,7 +253,6 @@ loop:
// We'll check ONVIF capabilitites anyhow.. Verify if we have PTZ, presets and inputs/outputs.
// For the inputs we will keep track of a the inputs and outputs state.
onvifEnabled := "false"
onvifZoom := "false"
onvifPanTilt := "false"
@@ -262,6 +263,7 @@ loop:
cameraConfiguration := configuration.Config.Capture.IPCamera
device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil {
// We will try to retrieve the PTZ configurations from the device.
onvifEnabled = "true"
configurations, err := onvif.GetPTZConfigurationsFromDevice(device)
if err == nil {
@@ -296,8 +298,22 @@ loop:
// We will also fetch some events, to know the status of the inputs and outputs.
// More event types might be added.
if pullPointAddress != "" {
events, err := onvif.GetEventMessages(device, pullPointAddress)
// -- We have two differen pull point subscriptions, one for the initials events and one for the loop.
// -- Some cameras do send recurrent events, others don't.
// a. For some older Hikvision models, events are send repeatedly (if input is high) with the strong state (set to false).
// - In this scenarion we are using a polling mechanism and set a timestamp to understand if the input is still active.
// b. For some newer Hikvision models, Avigilon, events are send only once (if state is set active).
// - In this scenario we are creating a new subscription to retrieve the initial (current) state of the inputs and outputs.
// Get a new pull point address, to get the initiatal state of the inputs and outputs.
pullPointAddressInitialState, err := onvif.CreatePullPointSubscription(device)
if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error())
}
if pullPointAddressInitialState != "" {
log.Log.Debug("cloud.HandleHeartBeat(): Fetching events from pullPointAddressInitialState")
events, err := onvif.GetEventMessages(device, pullPointAddressInitialState)
log.Log.Debug("cloud.HandleHeartBeat(): Completed fetching events from pullPointAddressInitialState")
if err == nil && len(events) > 0 {
onvifEventsList, err = json.Marshal(events)
if err != nil {
@@ -307,9 +323,28 @@ loop:
} else if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while getting events: " + err.Error())
onvifEventsList = []byte("[]")
// Try to unsubscribe and subscribe again.
onvif.UnsubscribePullPoint(device, pullPointAddress)
pullPointAddress, err = onvif.CreatePullPointSubscription(device)
} else if len(events) == 0 {
log.Log.Debug("cloud.HandleHeartBeat(): no events found.")
onvifEventsList = []byte("[]")
}
onvif.UnsubscribePullPoint(device, pullPointAddressInitialState)
}
// We do a second run an a long-living subscription to get the events asynchronously.
if pullPointAddressLoopState != "" {
log.Log.Debug("cloud.HandleHeartBeat(): Fetching events from pullPointAddressLoopState")
events, err := onvif.GetEventMessages(device, pullPointAddressLoopState)
log.Log.Debug("cloud.HandleHeartBeat(): Completed fetching events from pullPointAddressLoopState")
if err == nil && len(events) > 0 {
onvifEventsList, err = json.Marshal(events)
if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while marshalling events: " + err.Error())
onvifEventsList = []byte("[]")
}
} else if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while getting events: " + err.Error())
onvifEventsList = []byte("[]")
pullPointAddressLoopState, err = onvif.CreatePullPointSubscription(device)
if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error())
}
@@ -319,15 +354,55 @@ loop:
}
} else {
log.Log.Debug("cloud.HandleHeartBeat(): no pull point address found.")
onvifEventsList = []byte("[]")
// Try again
pullPointAddress, err = onvif.CreatePullPointSubscription(device)
pullPointAddressLoopState, err = onvif.CreatePullPointSubscription(device)
if err != nil {
log.Log.Debug("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error())
log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error())
}
}
// It also might be that events are not supported by the camera, in that case we will try to get the digital inputs and outputs.
// Through the `device` API, the `GetDigitalInputs` and `GetDigitalOutputs` functions are called.
// The disadvantage of this approach is that we don't have the state of the inputs and outputs (which is crazy..)
if pullPointAddressInitialState == "" && pullPointAddressLoopState == "" {
var events []onvif.ONVIFEvents
outputs, err := onvif.GetRelayOutputs(device)
if err != nil {
log.Log.Debug("cloud.HandleHeartBeat(): error while getting relay outputs: " + err.Error())
} else {
for _, output := range outputs.RelayOutputs {
event := onvif.ONVIFEvents{
Key: string(output.Token),
Value: "false",
Type: "output",
Timestamp: time.Now().Unix(),
}
events = append(events, event)
}
}
inputs, err := onvif.GetDigitalInputs(device)
if err != nil {
log.Log.Debug("cloud.HandleHeartBeat(): error while getting digital inputs: " + err.Error())
} else {
for _, input := range inputs.DigitalInputs {
event := onvif.ONVIFEvents{
Key: string(input.Token),
Value: "false",
Type: "input",
Timestamp: time.Now().Unix(),
}
events = append(events, event)
}
}
// Marshal the events
onvifEventsList, err = json.Marshal(events)
if err != nil {
log.Log.Error("cloud.HandleHeartBeat(): error while marshalling events: " + err.Error())
onvifEventsList = []byte("[]")
}
}
} else {
log.Log.Error("cloud.HandleHeartBeat(): error while connecting to ONVIF device: " + err.Error())
onvifPresetsList = []byte("[]")
@@ -395,6 +470,16 @@ loop:
hasBackChannel = "true"
}
hub_encryption := "false"
if config.HubEncryption == "true" {
hub_encryption = "true"
}
e2e_encryption := "false"
if config.Encryption != nil && config.Encryption.Enabled == "true" {
e2e_encryption = "true"
}
// We will formated the uptime to a human readable format
// this will be used on Kerberos Hub: Uptime -> 1 day and 2 hours.
uptimeFormatted := uptimeStart.Format("2006-01-02 15:04:05")
@@ -411,7 +496,9 @@ loop:
var object = fmt.Sprintf(`{
"key" : "%s",
"version" : "3.0.0",
"version" : "%s",
"hub_encryption": "%s",
"e2e_encryption": "%s",
"release" : "%s",
"cpuid" : "%s",
"clouduser" : "%s",
@@ -447,12 +534,11 @@ loop:
"docker" : true,
"kios" : false,
"raspberrypi" : false
}`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, onvifEventsList, cameraConnected, hasBackChannel)
}`, config.Key, kerberosAgentVersion, hub_encryption, e2e_encryption, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, onvifEventsList, cameraConnected, hasBackChannel)
// Get the private key to encrypt the data using symmetric encryption: AES.
HubEncryption := config.HubEncryption
privateKey := config.HubPrivateKey
if HubEncryption == "true" && privateKey != "" {
if hub_encryption == "true" && privateKey != "" {
// Encrypt the data using AES.
encrypted, err := encryption.AesEncrypt([]byte(object), privateKey)
if err != nil {
@@ -499,7 +585,7 @@ loop:
var object = fmt.Sprintf(`{
"key" : "%s",
"version" : "3.0.0",
"version" : "%s",
"release" : "%s",
"cpuid" : "%s",
"clouduser" : "%s",
@@ -533,7 +619,7 @@ loop:
"docker" : true,
"kios" : false,
"raspberrypi" : false
}`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, cameraConnected)
}`, config.Key, kerberosAgentVersion, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, cameraConnected)
var jsonStr = []byte(object)
buffy := bytes.NewBuffer(jsonStr)
@@ -561,11 +647,11 @@ loop:
}
}
if pullPointAddress != "" {
if pullPointAddressLoopState != "" {
cameraConfiguration := configuration.Config.Capture.IPCamera
device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
if err == nil {
onvif.UnsubscribePullPoint(device, pullPointAddress)
if err != nil {
onvif.UnsubscribePullPoint(device, pullPointAddressLoopState)
}
}
@@ -681,6 +767,79 @@ func HandleLiveStreamHD(livestreamCursor *packets.QueueCursor, configuration *mo
}
}
func HandleRealtimeProcessing(processingCursor *packets.QueueCursor, configuration *models.Configuration, communication *models.Communication, mqttClient mqtt.Client, rtspClient capture.RTSPClient) {
log.Log.Debug("cloud.RealtimeProcessing(): started")
config := configuration.Config
// If offline made is enabled, we will stop the thread.
if config.Offline == "true" {
log.Log.Debug("cloud.RealtimeProcessing(): stopping as Offline is enabled.")
} else {
// Check if we need to enable the realtime processing
if config.RealtimeProcessing == "true" {
hubKey := ""
if config.Cloud == "s3" && config.S3 != nil && config.S3.Publickey != "" {
hubKey = config.S3.Publickey
} else if config.Cloud == "kstorage" && config.KStorage != nil && config.KStorage.CloudKey != "" {
hubKey = config.KStorage.CloudKey
}
// This is the new way ;)
if config.HubKey != "" {
hubKey = config.HubKey
}
// We will publish the keyframes to the MQTT topic.
realtimeProcessingTopic := "kerberos/keyframes/" + hubKey
if config.RealtimeProcessingTopic != "" {
realtimeProcessingTopic = config.RealtimeProcessingTopic
}
var cursorError error
var pkt packets.Packet
for cursorError == nil {
pkt, cursorError = processingCursor.ReadPacket()
if len(pkt.Data) == 0 || !pkt.IsKeyFrame {
continue
}
log.Log.Info("cloud.RealtimeProcessing(): Sending base64 encoded images to MQTT.")
img, err := rtspClient.DecodePacket(pkt)
if err == nil {
bytes, _ := utils.ImageToBytes(&img)
encoded := base64.StdEncoding.EncodeToString(bytes)
valueMap := make(map[string]interface{})
valueMap["image"] = encoded
message := models.Message{
Payload: models.Payload{
Action: "receive-keyframe",
DeviceId: configuration.Config.Key,
Value: valueMap,
},
}
payload, err := models.PackageMQTTMessage(configuration, message)
if err == nil {
mqttClient.Publish(realtimeProcessingTopic, 0, false, payload)
} else {
log.Log.Info("cloud.RealtimeProcessing(): something went wrong while sending acknowledge config to hub: " + string(payload))
}
}
}
} else {
log.Log.Debug("cloud.RealtimeProcessing(): stopping as Liveview is disabled.")
}
}
log.Log.Debug("cloud.HandleLiveStreamSD(): finished")
}
// VerifyHub godoc
// @Router /api/hub/verify [post]
// @ID verify-hub

View File

@@ -188,7 +188,7 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
time.Sleep(time.Second * 3)
return status
}
log.Log.Info("components.Kerberos.RunAgent(): opened RTSP sub stream: " + rtspUrl)
log.Log.Info("components.Kerberos.RunAgent(): opened RTSP sub stream: " + subRtspUrl)
// Get the video streams from the RTSP server.
videoSubStreams, err = rtspSubClient.GetVideoStreams()
@@ -206,42 +206,8 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
height := videoSubStream.Height
// Set config values as well
configuration.Config.Capture.IPCamera.Width = width
configuration.Config.Capture.IPCamera.Height = height
}
if cameraSettings.RTSP != rtspUrl ||
cameraSettings.SubRTSP != subRtspUrl ||
cameraSettings.Width != width ||
cameraSettings.Height != height {
// TODO: this condition is used to reset the decoder when the camera settings change.
// The main idea is that you only set the decoder once, and then reuse it on each restart (no new memory allocation).
// However the stream settings of the camera might have been changed, and so the decoder might need to be reloaded.
// .... Not used for the moment ....
if cameraSettings.RTSP != "" && cameraSettings.SubRTSP != "" && cameraSettings.Initialized {
//decoder.Close()
//if subStreamEnabled {
// subDecoder.Close()
//}
}
// At some routines we will need to decode the image.
// Make sure its properly locked as we only have a single decoder.
log.Log.Info("components.Kerberos.RunAgent(): camera settings changed, reloading decoder")
//capture.GetVideoDecoder(decoder, streams)
//if subStreamEnabled {
// capture.GetVideoDecoder(subDecoder, subStreams)
//}
cameraSettings.RTSP = rtspUrl
cameraSettings.SubRTSP = subRtspUrl
cameraSettings.Width = width
cameraSettings.Height = height
cameraSettings.Initialized = true
} else {
log.Log.Info("components.Kerberos.RunAgent(): camera settings did not change, keeping decoder")
configuration.Config.Capture.IPCamera.SubWidth = width
configuration.Config.Capture.IPCamera.SubHeight = height
}
// We are creating a queue to store the RTSP frames in, these frames will be
@@ -270,7 +236,7 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
if subStreamEnabled && rtspSubClient != nil {
subQueue = packets.NewQueue()
communication.SubQueue = subQueue
subQueue.SetMaxGopCount(1) // GOP time frame is set to prerecording (we'll add 2 gops to leave some room).
subQueue.SetMaxGopCount(3) // GOP time frame is set to prerecording (we'll add 2 gops to leave some room).
subQueue.WriteHeader(videoSubStreams)
go rtspSubClient.Start(context.Background(), "sub", subQueue, configuration, communication)
@@ -310,6 +276,15 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
go computervision.ProcessMotion(motionCursor, configuration, communication, mqttClient, rtspClient)
}
// Handle realtime processing if enabled.
if subStreamEnabled {
realtimeProcessingCursor := subQueue.Latest()
go cloud.HandleRealtimeProcessing(realtimeProcessingCursor, configuration, communication, mqttClient, rtspClient)
} else {
realtimeProcessingCursor := queue.Latest()
go cloud.HandleRealtimeProcessing(realtimeProcessingCursor, configuration, communication, mqttClient, rtspClient)
}
// Handle Upload to cloud provider (Kerberos Hub, Kerberos Vault and others)
go cloud.HandleUpload(configDirectory, configuration, communication)
@@ -348,9 +323,20 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
// Here we are cleaning up everything!
if configuration.Config.Offline != "true" {
communication.HandleUpload <- "stop"
select {
case communication.HandleUpload <- "stop":
log.Log.Info("components.Kerberos.RunAgent(): stopping upload")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RunAgent(): stopping upload timed out")
}
}
select {
case communication.HandleStream <- "stop":
log.Log.Info("components.Kerberos.RunAgent(): stopping stream")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RunAgent(): stopping stream timed out")
}
communication.HandleStream <- "stop"
// We use the steam channel to stop both main and sub stream.
//if subStreamEnabled {
// communication.HandleSubStream <- "stop"
@@ -442,8 +428,12 @@ func ControlAgent(communication *models.Communication) {
// After 15 seconds without activity this is thrown..
if occurence == 3 {
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking mainstream.")
communication.HandleBootstrap <- "restart"
time.Sleep(2 * time.Second)
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream timed out")
}
occurence = 0
}
@@ -464,9 +454,12 @@ func ControlAgent(communication *models.Communication) {
// After 15 seconds without activity this is thrown..
if occurenceSub == 3 {
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
communication.HandleBootstrap <- "restart"
time.Sleep(2 * time.Second)
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream timed out")
}
occurenceSub = 0
}
}
@@ -603,7 +596,12 @@ func GetDays(c *gin.Context, configDirectory string, configuration *models.Confi
// @Success 200 {object} models.APIResponse
func StopAgent(c *gin.Context, communication *models.Communication) {
log.Log.Info("components.Kerberos.StopAgent(): sending signal to stop agent, this will os.Exit(0).")
communication.HandleBootstrap <- "stop"
select {
case communication.HandleBootstrap <- "stop":
log.Log.Info("components.Kerberos.StopAgent(): Stopping machinery.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.StopAgent(): Stopping machinery timed out")
}
c.JSON(200, gin.H{
"stopped": true,
})
@@ -618,7 +616,12 @@ func StopAgent(c *gin.Context, communication *models.Communication) {
// @Success 200 {object} models.APIResponse
func RestartAgent(c *gin.Context, communication *models.Communication) {
log.Log.Info("components.Kerberos.RestartAgent(): sending signal to restart agent.")
communication.HandleBootstrap <- "restart"
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.RestartAgent(): Restarting machinery.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RestartAgent(): Restarting machinery timed out")
}
c.JSON(200, gin.H{
"restarted": true,
})

View File

@@ -87,7 +87,6 @@ func WriteFileToBackChannel(infile av.DemuxCloser) {
break
}
// Send to backchannel
fmt.Println(buffer)
infile.Write(buffer, 2, uint32(count))
count = count + 1024

View File

@@ -59,7 +59,7 @@ func OpenConfig(configDirectory string, configuration *models.Configuration) {
// Write to mongodb
client := database.New()
db := client.Database(database.DatabaseName)
db := client.Client.Database(database.DatabaseName)
collection := db.Collection("configuration")
var globalConfig models.Config
@@ -382,10 +382,21 @@ func OverrideWithEnvironmentVariables(configuration *models.Configuration) {
configuration.Config.MQTTPassword = value
break
/* Real-time streaming of keyframes to a MQTT topic */
case "AGENT_REALTIME_PROCESSING":
configuration.Config.RealtimeProcessing = value
break
case "AGENT_REALTIME_PROCESSING_TOPIC":
configuration.Config.RealtimeProcessingTopic = value
break
/* WebRTC settings for live-streaming (remote) */
case "AGENT_STUN_URI":
configuration.Config.STUNURI = value
break
case "AGENT_FORCE_TURN":
configuration.Config.ForceTurn = value
break
case "AGENT_TURN_URI":
configuration.Config.TURNURI = value
break
@@ -485,7 +496,9 @@ func SaveConfig(configDirectory string, config models.Config, configuration *mod
if communication.CameraConnected {
select {
case communication.HandleBootstrap <- "restart":
default:
log.Log.Info("config.main.SaveConfig(): update config, restart agent.")
case <-time.After(1 * time.Second):
log.Log.Info("config.main.SaveConfig(): update config, restart agent.")
}
}
@@ -512,7 +525,7 @@ func StoreConfig(configDirectory string, config models.Config) error {
// Write to mongodb
client := database.New()
db := client.Database(database.DatabaseName)
db := client.Client.Database(database.DatabaseName)
collection := db.Collection("configuration")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

View File

@@ -15,12 +15,19 @@ type DB struct {
Client *mongo.Client
}
var TIMEOUT = 10 * time.Second
var _init_ctx sync.Once
var _instance *DB
var DatabaseName = "KerberosFactory"
func New() *mongo.Client {
var DatabaseName = os.Getenv("MONGODB_DATABASE_FACTORY")
func New() *DB {
if DatabaseName == "" {
DatabaseName = "KerberosFactory"
}
mongodbURI := os.Getenv("MONGODB_URI")
host := os.Getenv("MONGODB_HOST")
databaseCredentials := os.Getenv("MONGODB_DATABASE_CREDENTIALS")
replicaset := os.Getenv("MONGODB_REPLICASET")
@@ -28,28 +35,46 @@ func New() *mongo.Client {
password := os.Getenv("MONGODB_PASSWORD")
authentication := "SCRAM-SHA-256"
ctx, cancel := context.WithTimeout(context.Background(), TIMEOUT)
defer cancel()
_init_ctx.Do(func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_instance = new(DB)
mongodbURI := fmt.Sprintf("mongodb://%s:%s@%s", username, password, host)
if replicaset != "" {
mongodbURI = fmt.Sprintf("%s/?replicaSet=%s", mongodbURI, replicaset)
}
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongodbURI).SetAuth(options.Credential{
AuthMechanism: authentication,
AuthSource: databaseCredentials,
Username: username,
Password: password,
}))
if err != nil {
fmt.Printf("Error setting up mongodb connection: %+v\n", err)
os.Exit(1)
// We can also apply the complete URI
// e.g. "mongodb+srv://<username>:<password>@kerberos-hub.shhng.mongodb.net/?retryWrites=true&w=majority&appName=kerberos-hub"
if mongodbURI != "" {
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(mongodbURI).SetServerAPIOptions(serverAPI)
// Create a new client and connect to the server
client, err := mongo.Connect(ctx, opts)
if err != nil {
fmt.Printf("Error setting up mongodb connection: %+v\n", err)
os.Exit(1)
}
_instance.Client = client
} else {
// New MongoDB driver
mongodbURI := fmt.Sprintf("mongodb://%s:%s@%s", username, password, host)
if replicaset != "" {
mongodbURI = fmt.Sprintf("%s/?replicaSet=%s", mongodbURI, replicaset)
}
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongodbURI).SetAuth(options.Credential{
AuthMechanism: authentication,
AuthSource: databaseCredentials,
Username: username,
Password: password,
}))
if err != nil {
fmt.Printf("Error setting up mongodb connection: %+v\n", err)
os.Exit(1)
}
_instance.Client = client
}
_instance.Client = client
})
return _instance.Client
return _instance
}

View File

@@ -76,7 +76,6 @@ func ConfigureLogrus(level string, output string, timezone *time.Location) {
logLevel = logrus.ErrorLevel
} else if level == "debug" {
logLevel = logrus.DebugLevel
logrus.SetReportCaller(true)
} else if level == "fatal" {
logLevel = logrus.FatalLevel
} else if level == "warning" {

View File

@@ -12,38 +12,41 @@ type Configuration struct {
// Config is the highlevel struct which contains all the configuration of
// your Kerberos Open Source instance.
type Config struct {
Type string `json:"type"`
Key string `json:"key"`
Name string `json:"name"`
FriendlyName string `json:"friendly_name"`
Time string `json:"time" bson:"time"`
Offline string `json:"offline"`
AutoClean string `json:"auto_clean"`
RemoveAfterUpload string `json:"remove_after_upload"`
MaxDirectorySize int64 `json:"max_directory_size"`
Timezone string `json:"timezone"`
Capture Capture `json:"capture"`
Timetable []*Timetable `json:"timetable"`
Region *Region `json:"region"`
Cloud string `json:"cloud" bson:"cloud"`
S3 *S3 `json:"s3,omitempty" bson:"s3,omitempty"`
KStorage *KStorage `json:"kstorage,omitempty" bson:"kstorage,omitempty"`
Dropbox *Dropbox `json:"dropbox,omitempty" bson:"dropbox,omitempty"`
MQTTURI string `json:"mqtturi" bson:"mqtturi,omitempty"`
MQTTUsername string `json:"mqtt_username" bson:"mqtt_username"`
MQTTPassword string `json:"mqtt_password" bson:"mqtt_password"`
STUNURI string `json:"stunuri" bson:"stunuri"`
TURNURI string `json:"turnuri" bson:"turnuri"`
TURNUsername string `json:"turn_username" bson:"turn_username"`
TURNPassword string `json:"turn_password" bson:"turn_password"`
HeartbeatURI string `json:"heartbeaturi" bson:"heartbeaturi"` /*obsolete*/
HubEncryption string `json:"hub_encryption" bson:"hub_encryption"`
HubURI string `json:"hub_uri" bson:"hub_uri"`
HubKey string `json:"hub_key" bson:"hub_key"`
HubPrivateKey string `json:"hub_private_key" bson:"hub_private_key"`
HubSite string `json:"hub_site" bson:"hub_site"`
ConditionURI string `json:"condition_uri" bson:"condition_uri"`
Encryption *Encryption `json:"encryption,omitempty" bson:"encryption,omitempty"`
Type string `json:"type"`
Key string `json:"key"`
Name string `json:"name"`
FriendlyName string `json:"friendly_name"`
Time string `json:"time" bson:"time"`
Offline string `json:"offline"`
AutoClean string `json:"auto_clean"`
RemoveAfterUpload string `json:"remove_after_upload"`
MaxDirectorySize int64 `json:"max_directory_size"`
Timezone string `json:"timezone"`
Capture Capture `json:"capture"`
Timetable []*Timetable `json:"timetable"`
Region *Region `json:"region"`
Cloud string `json:"cloud" bson:"cloud"`
S3 *S3 `json:"s3,omitempty" bson:"s3,omitempty"`
KStorage *KStorage `json:"kstorage,omitempty" bson:"kstorage,omitempty"`
Dropbox *Dropbox `json:"dropbox,omitempty" bson:"dropbox,omitempty"`
MQTTURI string `json:"mqtturi" bson:"mqtturi,omitempty"`
MQTTUsername string `json:"mqtt_username" bson:"mqtt_username"`
MQTTPassword string `json:"mqtt_password" bson:"mqtt_password"`
STUNURI string `json:"stunuri" bson:"stunuri"`
ForceTurn string `json:"turn_force" bson:"turn_force"`
TURNURI string `json:"turnuri" bson:"turnuri"`
TURNUsername string `json:"turn_username" bson:"turn_username"`
TURNPassword string `json:"turn_password" bson:"turn_password"`
HeartbeatURI string `json:"heartbeaturi" bson:"heartbeaturi"` /*obsolete*/
HubEncryption string `json:"hub_encryption" bson:"hub_encryption"`
HubURI string `json:"hub_uri" bson:"hub_uri"`
HubKey string `json:"hub_key" bson:"hub_key"`
HubPrivateKey string `json:"hub_private_key" bson:"hub_private_key"`
HubSite string `json:"hub_site" bson:"hub_site"`
ConditionURI string `json:"condition_uri" bson:"condition_uri"`
Encryption *Encryption `json:"encryption,omitempty" bson:"encryption,omitempty"`
RealtimeProcessing string `json:"realtimeprocessing,omitempty" bson:"realtimeprocessing,omitempty"`
RealtimeProcessingTopic string `json:"realtimeprocessing_topic" bson:"realtimeprocessing_topic"`
}
// Capture defines which camera type (Id) you are using (IP, USB or Raspberry Pi camera),
@@ -72,11 +75,14 @@ type Capture struct {
// IPCamera configuration, such as the RTSP url of the IPCamera and the FPS.
// Also includes ONVIF integration
type IPCamera struct {
RTSP string `json:"rtsp"`
Width int `json:"width"`
Height int `json:"height"`
FPS string `json:"fps"`
RTSP string `json:"rtsp"`
SubRTSP string `json:"sub_rtsp"`
SubWidth int `json:"sub_width"`
SubHeight int `json:"sub_height"`
SubFPS string `json:"sub_fps"`
ONVIF string `json:"onvif,omitempty" bson:"onvif"`
ONVIFXAddr string `json:"onvif_xaddr" bson:"onvif_xaddr"`
ONVIFUsername string `json:"onvif_username" bson:"onvif_username"`

View File

@@ -27,31 +27,13 @@ func PackageMQTTMessage(configuration *Configuration, msg Message) ([]byte, erro
msg.DeviceId = msg.Payload.DeviceId
msg.Timestamp = time.Now().Unix()
// We'll hide the message (by default in latest version)
// We will encrypt using the Kerberos Hub private key if set.
/*msg.Hidden = false
if configuration.Config.HubPrivateKey != "" {
msg.Hidden = true
pload := msg.Payload
// Pload to base64
data, err := json.Marshal(pload)
if err != nil {
msg.Hidden = false
} else {
k := configuration.Config.Encryption.SymmetricKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
msg.Payload.HiddenValue = data
msg.Payload.Value = make(map[string]interface{})
}
}
}*/
// Configuration
config := configuration.Config
// Next to hiding the message, we can also encrypt it using your own private key.
// Which is not stored in a remote environment (hence you are the only one owning it).
msg.Encrypted = false
if configuration.Config.Encryption != nil && configuration.Config.Encryption.Enabled == "true" {
if config.Encryption != nil && config.Encryption.Enabled == "true" {
msg.Encrypted = true
}
msg.PublicKey = ""
@@ -85,19 +67,47 @@ func PackageMQTTMessage(configuration *Configuration, msg Message) ([]byte, erro
rsaKey, _ := key.(*rsa.PrivateKey)
// Create a 16bit key random
k := configuration.Config.Encryption.SymmetricKey
if config.Encryption != nil && config.Encryption.SymmetricKey != "" {
k := config.Encryption.SymmetricKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
// Sign the encrypted value
signature, err := encryption.SignWithPrivateKey([]byte(data), rsaKey)
if err == nil {
base64Signature := base64.StdEncoding.EncodeToString(signature)
msg.Payload.EncryptedValue = data
msg.Payload.Signature = base64Signature
msg.Payload.Value = make(map[string]interface{})
}
}
}
}
}
// We'll hide the message (by default in latest version)
// We will encrypt using the Kerberos Hub private key if set.
msg.Hidden = false
if config.HubEncryption == "true" && config.HubPrivateKey != "" {
msg.Hidden = true
}
if msg.Hidden {
pload := msg.Payload
// Pload to base64
data, err := json.Marshal(pload)
if err != nil {
msg.Hidden = false
} else {
k := config.HubPrivateKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
// Sign the encrypted value
signature, err := encryption.SignWithPrivateKey([]byte(data), rsaKey)
if err == nil {
base64Signature := base64.StdEncoding.EncodeToString(signature)
msg.Payload.EncryptedValue = data
msg.Payload.Signature = base64Signature
msg.Payload.Value = make(map[string]interface{})
}
msg.Payload.HiddenValue = data
msg.Payload.EncryptedValue = ""
msg.Payload.Signature = ""
msg.Payload.Value = make(map[string]interface{})
}
}
}

View File

@@ -200,9 +200,19 @@ func ConnectToOnvifDevice(cameraConfiguration *models.IPCamera) (*onvif.Device,
var capabilities device.GetCapabilitiesResponse
if err != nil {
log.Log.Debug("onvif.ConnectToOnvifDevice(): " + err.Error())
} else {
// Try again with other authentication mode
dev, err = onvif.NewDevice(onvif.DeviceParams{
Xaddr: cameraConfiguration.ONVIFXAddr,
Username: cameraConfiguration.ONVIFUsername,
Password: cameraConfiguration.ONVIFPassword,
AuthMode: "digest",
})
if err != nil {
log.Log.Debug("onvif.ConnectToOnvifDevice(): " + err.Error())
}
}
if err == nil {
getCapabilities := device.GetCapabilities{Category: []xsdonvif.CapabilityCategory{"All"}}
resp, err := dev.CallMethod(getCapabilities)
if err != nil {
@@ -798,14 +808,16 @@ func GetPresetsFromDevice(device *onvif.Device) ([]models.OnvifActionPreset, err
return presets, err
}
presetsList := ""
for _, preset := range presetsResponse.Preset {
log.Log.Debug("onvif.main.GetPresetsFromDevice(): " + string(preset.Name) + " (" + string(preset.Token) + ")")
p := models.OnvifActionPreset{
Name: string(preset.Name),
Token: string(preset.Token),
}
presetsList += string(preset.Name) + " (" + string(preset.Token) + "), "
presets = append(presets, p)
}
log.Log.Debug("onvif.main.GetPresetsFromDevice(): " + presetsList)
return presets, err
}
@@ -980,7 +992,8 @@ func CreatePullPointSubscription(dev *onvif.Device) (string, error) {
Filter: &event.FilterType{
TopicExpression: &event.TopicExpressionType{
Dialect: xsd.String("http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"),
TopicKinds: "tns1:Device/Trigger//.",
TopicKinds: "tns1:Device/Trigger//.", // -> This works for Avigilon, Hanwa, Hikvision
// TopicKinds: "//.", -> This works for Axis, but throws other errors.
},
},
})
@@ -1037,14 +1050,10 @@ func GetInputOutputs() ([]ONVIFEvents, error) {
// We have some odd behaviour for inputs: the logical state is set to false even if circuit is closed. However we do see repeated events (looks like heartbeats).
// We are assuming that if we do not receive an event for 15 seconds the input is inactive, otherwise we set to active.
for key, value := range inputOutputDeviceMap {
if value.Type == "input" {
if time.Now().Unix()-value.Timestamp > 15 {
value.Value = "false"
} else {
value.Value = "true"
}
inputOutputDeviceMap[key] = value
if time.Now().Unix()-value.Timestamp < 15 && value.Value == "false" {
value.Value = "true"
}
inputOutputDeviceMap[key] = value
eventsArray = append(eventsArray, *value)
}
for _, value := range eventsArray {
@@ -1070,7 +1079,7 @@ func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents
// Pull message
pullMessage := event.PullMessages{
Timeout: xsd.Duration("PT5S"),
MessageLimit: 100,
MessageLimit: 10,
}
requestBody, err := xml.Marshal(pullMessage)
if err != nil {
@@ -1104,13 +1113,18 @@ func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents
for _, message := range pullMessagesResponse.NotificationMessage {
log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Topic.TopicKinds))
log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Message.Message.Data.SimpleItem[0].Name) + " " + string(message.Message.Message.Data.SimpleItem[0].Value))
if message.Topic.TopicKinds == "tns1:Device/Trigger/Relay" {
//if len(message.Message.Message.Data.SimpleItem) > 0 {
// log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Message.Message.Data.SimpleItem[0].Name) + " " + string(message.Message.Message.Data.SimpleItem[0].Value))
//}
if message.Topic.TopicKinds == "tns1:Device/Trigger/Relay" ||
message.Topic.TopicKinds == "tns1:Device/tns1:Trigger/tns1:Relay" { // This is for avigilon cameras
if len(message.Message.Message.Data.SimpleItem) > 0 {
if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" {
if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" ||
message.Message.Message.Data.SimpleItem[0].Name == "RelayLogicalState" { // On avigilon it's called RelayLogicalState
key := string(message.Message.Message.Source.SimpleItem[0].Value)
value := string(message.Message.Message.Data.SimpleItem[0].Value)
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) output: " + key + " " + value)
propertyOperation := string(message.Message.Message.PropertyOperation)
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) output: " + key + " " + value + " (" + propertyOperation + ")")
// Depending on the onvif library they might use different values for active and inactive.
if value == "active" || value == "1" {
@@ -1121,26 +1135,30 @@ func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents
// Check if key exists in map
// If it does not exist we'll add it to the map otherwise we'll update the value.
if _, ok := inputOutputDeviceMap[key]; !ok {
inputOutputDeviceMap[key] = &ONVIFEvents{
Key: key,
if _, ok := inputOutputDeviceMap[key+"-output"]; !ok {
inputOutputDeviceMap[key+"-output"] = &ONVIFEvents{
Key: key + "-output",
Type: "output",
Value: value,
Timestamp: 0,
}
} else {
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) output: " + key + " " + value)
inputOutputDeviceMap[key].Value = value
inputOutputDeviceMap[key].Timestamp = time.Now().Unix()
} else if propertyOperation == "Changed" {
inputOutputDeviceMap[key+"-output"].Value = value
inputOutputDeviceMap[key+"-output"].Timestamp = time.Now().Unix()
} else if propertyOperation == "Initialized" {
inputOutputDeviceMap[key+"-output"].Value = value
}
}
}
} else if message.Topic.TopicKinds == "tns1:Device/Trigger/DigitalInput" {
} else if message.Topic.TopicKinds == "tns1:Device/Trigger/DigitalInput" ||
message.Topic.TopicKinds == "tns1:Device/tns1:Trigger/tnssamsung:DigitalInput" { // This is for avigilon's camera
if len(message.Message.Message.Data.SimpleItem) > 0 {
if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" {
if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" ||
message.Message.Message.Data.SimpleItem[0].Name == "Level" { // On avigilon it's called level
key := string(message.Message.Message.Source.SimpleItem[0].Value)
value := string(message.Message.Message.Data.SimpleItem[0].Value)
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) input: " + key + " " + value)
propertyOperation := string(message.Message.Message.PropertyOperation)
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) input: " + key + " " + value + " (" + propertyOperation + ")")
// Depending on the onvif library they might use different values for active and inactive.
if value == "active" || value == "1" {
@@ -1151,17 +1169,18 @@ func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents
// Check if key exists in map
// If it does not exist we'll add it to the map otherwise we'll update the value.
if _, ok := inputOutputDeviceMap[key]; !ok {
inputOutputDeviceMap[key] = &ONVIFEvents{
Key: key,
if _, ok := inputOutputDeviceMap[key+"-input"]; !ok {
inputOutputDeviceMap[key+"-input"] = &ONVIFEvents{
Key: key + "-input",
Type: "input",
Value: value,
Timestamp: 0,
}
} else {
log.Log.Debug("onvif.main.GetEventMessages(pullMessages) input: " + key + " " + value)
inputOutputDeviceMap[key].Value = value
inputOutputDeviceMap[key].Timestamp = time.Now().Unix()
} else if propertyOperation == "Changed" {
inputOutputDeviceMap[key+"-input"].Value = value
inputOutputDeviceMap[key+"-input"].Timestamp = time.Now().Unix()
} else if propertyOperation == "Initialized" {
inputOutputDeviceMap[key+"-input"].Value = value
}
}
}
@@ -1249,8 +1268,8 @@ func TriggerRelayOutput(dev *onvif.Device, output string) (err error) {
// However in theory there might be multiple outputs. We might need to change
// this in the future "kerberos-io/onvif" library.
if err == nil {
token := relayoutputs.RelayOutputs.Token
if output == string(token) {
token := relayoutputs.RelayOutputs[0].Token
if output == string(token+"-output") {
outputState := device.SetRelayOutputState{
RelayOutputToken: token,
LogicalState: "active",

View File

@@ -9,12 +9,13 @@ import (
// Packet represents an RTP Packet
type Packet struct {
Packet *rtp.Packet
IsAudio bool // packet is audio
IsVideo bool // packet is video
IsKeyFrame bool // video packet is key frame
Idx int8 // stream index in container format
Codec string // codec name
CompositionTime time.Duration // packet presentation time minus decode time for H264 B-Frame
Time time.Duration // packet decode time
Data []byte // packet data
IsAudio bool // packet is audio
IsVideo bool // packet is video
IsKeyFrame bool // video packet is key frame
Idx int8 // stream index in container format
Codec string // codec name
CompositionTime int64 // packet presentation time minus decode time for H264 B-Frame
Time int64 // packet decode time
TimeLegacy time.Duration
Data []byte // packet data
}

View File

@@ -4,7 +4,6 @@ package packets
import (
"io"
"sync"
"time"
)
// time
@@ -145,7 +144,7 @@ func (self *Queue) Oldest() *QueueCursor {
}
// Create cursor position at specific time in buffered packets.
func (self *Queue) DelayedTime(dur time.Duration) *QueueCursor {
func (self *Queue) DelayedTime(dur int64) *QueueCursor {
cursor := self.newCursor()
cursor.init = func(buf *Buf, videoidx int) BufPos {
i := buf.Tail - 1

View File

@@ -395,7 +395,9 @@ func DoGetDigitalInputs(c *gin.Context) {
}
cameraConfiguration := configuration.Config.Capture.IPCamera
_, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration)
onvifInputs, _ := onvif.GetDigitalInputs(device)
if err == nil {
// Get the digital inputs and outputs from the device
inputOutputs, err := onvif.GetInputOutputs()
@@ -408,6 +410,24 @@ func DoGetDigitalInputs(c *gin.Context) {
inputs = append(inputs, event)
}
}
// Iterate over inputs from onvif and compare
for _, input := range onvifInputs.DigitalInputs {
find := false
for _, event := range inputs {
key := string(input.Token)
if key == event.Key {
find = true
}
}
if !find {
key := string(input.Token)
inputs = append(inputs, onvif.ONVIFEvents{
Key: key,
Type: "input",
})
}
}
c.JSON(200, gin.H{
"data": inputs,
})

View File

@@ -166,9 +166,33 @@ func MQTTListenerHandler(mqttClient mqtt.Client, hubKey string, configDirectory
// We will receive all messages from our hub, so we'll need to filter to the relevant device.
if message.Mid != "" && message.Timestamp != 0 && message.DeviceId == configuration.Config.Key {
// Messages might be encrypted, if so we'll
// need to decrypt them.
var payload models.Payload
// Messages might be hidden, if so we'll need to decrypt them using the Kerberos Hub private key.
if message.Hidden && configuration.Config.HubEncryption == "true" {
hiddenValue := message.Payload.HiddenValue
if len(hiddenValue) > 0 {
privateKey := configuration.Config.HubPrivateKey
if privateKey != "" {
data, err := base64.StdEncoding.DecodeString(hiddenValue)
if err != nil {
return
}
visibleValue, err := encryption.AesDecrypt(data, privateKey)
if err != nil {
log.Log.Error("routers.mqtt.main.MQTTListenerHandler(): error decrypting message: " + err.Error())
return
}
json.Unmarshal(visibleValue, &payload)
message.Payload = payload
} else {
log.Log.Error("routers.mqtt.main.MQTTListenerHandler(): error decrypting message, no private key provided.")
}
}
}
// Messages might be end-to-end encrypted, if so we'll need to decrypt them,
// using our own keys.
if message.Encrypted && configuration.Config.Encryption != nil && configuration.Config.Encryption.Enabled == "true" {
encryptedValue := message.Payload.EncryptedValue
if len(encryptedValue) > 0 {
@@ -352,16 +376,26 @@ func HandleRequestConfig(mqttClient mqtt.Client, hubKey string, payload models.P
json.Unmarshal(jsonData, &configPayload)
if configPayload.Timestamp != 0 {
// Get Config from the device
// Get Config from the device
key := configuration.Config.Key
name := configuration.Config.Name
if configuration.Config.FriendlyName != "" {
name = configuration.Config.FriendlyName
}
if key != "" && name != "" {
// Copy the config, as we don't want to share the encryption part.
deepCopy := configuration.Config
// We need a fix for the width and height if a substream.
// The ROI requires the width and height of the sub stream.
if configuration.Config.Capture.IPCamera.SubRTSP != "" {
deepCopy.Capture.IPCamera.Width = configuration.Config.Capture.IPCamera.SubWidth
deepCopy.Capture.IPCamera.Height = configuration.Config.Capture.IPCamera.SubHeight
}
var configMap map[string]interface{}
inrec, _ := json.Marshal(deepCopy)
json.Unmarshal(inrec, &configMap)

View File

@@ -161,6 +161,8 @@ logreader:
if err == nil {
bytes, _ := utils.ImageToBytes(&img)
encodedImage = base64.StdEncoding.EncodeToString(bytes)
} else {
continue
}
} else {
log.Log.Error("routers.websocket.main.ForwardSDStream():" + err.Error())

View File

@@ -23,6 +23,8 @@ import (
"github.com/kerberos-io/agent/machinery/src/models"
)
const VERSION = "3.2.6"
const letterBytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
// MaxUint8 - maximum value which can be held in an uint8

View File

@@ -9,14 +9,15 @@ import (
"sync/atomic"
"time"
//"github.com/izern/go-fdkaac/fdkaac"
"github.com/kerberos-io/agent/machinery/src/capture"
"github.com/kerberos-io/agent/machinery/src/log"
"github.com/kerberos-io/agent/machinery/src/models"
"github.com/kerberos-io/agent/machinery/src/packets"
mqtt "github.com/eclipse/paho.mqtt.golang"
pionWebRTC "github.com/pion/webrtc/v3"
pionMedia "github.com/pion/webrtc/v3/pkg/media"
pionWebRTC "github.com/pion/webrtc/v4"
pionMedia "github.com/pion/webrtc/v4/pkg/media"
)
var (
@@ -135,6 +136,11 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
api := pionWebRTC.NewAPI(pionWebRTC.WithMediaEngine(mediaEngine))
policy := pionWebRTC.ICETransportPolicyAll
if config.ForceTurn == "true" {
policy = pionWebRTC.ICETransportPolicyRelay
}
peerConnection, err := api.NewPeerConnection(
pionWebRTC.Configuration{
ICEServers: []pionWebRTC.ICEServer{
@@ -147,7 +153,7 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
Credential: w.TurnServersCredential,
},
},
//ICETransportPolicy: pionWebRTC.ICETransportPolicyRelay, // This will force a relay server, we might make this configurable.
ICETransportPolicy: policy,
},
)
@@ -222,6 +228,8 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
candateBinary, err := json.Marshal(candateJSON)
if err == nil {
valueMap["candidate"] = string(candateBinary)
valueMap["sdp"] = []byte(base64.StdEncoding.EncodeToString([]byte(answer.SDP)))
valueMap["session_id"] = handshake.SessionID
} else {
log.Log.Info("webrtc.main.InitializeWebRTCConnection(): something went wrong while marshalling candidate: " + err.Error())
}
@@ -250,6 +258,7 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
// Create a config map
valueMap := make(map[string]interface{})
valueMap["sdp"] = []byte(base64.StdEncoding.EncodeToString([]byte(answer.SDP)))
valueMap["session_id"] = handshake.SessionID
log.Log.Info("webrtc.main.InitializeWebRTCConnection(): Send SDP answer")
// We'll send the candidate to the hub
@@ -306,16 +315,22 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
// Later when we read a packet we need to figure out which track to send it to.
hasH264 := false
hasPCM_MULAW := false
hasAAC := false
hasOpus := false
streams, _ := rtspClient.GetStreams()
for _, stream := range streams {
if stream.Name == "H264" {
hasH264 = true
} else if stream.Name == "PCM_MULAW" {
hasPCM_MULAW = true
} else if stream.Name == "AAC" {
hasAAC = true
} else if stream.Name == "OPUS" {
hasOpus = true
}
}
if !hasH264 && !hasPCM_MULAW {
if !hasH264 && !hasPCM_MULAW && !hasAAC && !hasOpus {
log.Log.Error("webrtc.main.WriteToTrack(): no valid video codec and audio codec found.")
} else {
if config.Capture.TranscodingWebRTC == "true" {
@@ -326,7 +341,8 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
var cursorError error
var pkt packets.Packet
var previousTime time.Duration
//var previousTimeVideo int64
//var previousTimeAudio int64
start := false
receivedKeyFrame := false
@@ -336,14 +352,12 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
for cursorError == nil {
pkt, cursorError = livestreamCursor.ReadPacket()
bufferDuration := pkt.Time - previousTime
previousTime = pkt.Time
if config.Capture.ForwardWebRTC != "true" && peerConnectionCount == 0 {
start = false
receivedKeyFrame = false
continue
}
//if config.Capture.ForwardWebRTC != "true" && peerConnectionCount == 0 {
// start = false
// receivedKeyFrame = false
// continue
//}
select {
case lastKeepAlive = <-communication.HandleLiveHDKeepalive:
@@ -385,12 +399,18 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
//}
if pkt.IsVideo {
// Calculate the difference
//bufferDuration := pkt.Time - previousTimeVideo
//previousTimeVideo = pkt.Time
// Start at the first keyframe
if pkt.IsKeyFrame {
start = true
}
if start {
sample := pionMedia.Sample{Data: pkt.Data, Duration: bufferDuration}
//bufferDurationCasted := time.Duration(bufferDuration) * time.Millisecond
sample := pionMedia.Sample{Data: pkt.Data, PacketTimestamp: uint32(pkt.Time)}
if config.Capture.ForwardWebRTC == "true" {
// We will send the video to a remote peer
// TODO..
@@ -401,8 +421,24 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
}
}
} else if pkt.IsAudio {
// @TODO: We need to check if the audio is PCM_MULAW or AAC
// If AAC we need to transcode it to PCM_MULAW
// If PCM_MULAW we can send it directly.
if hasAAC {
// We will transcode the audio
// TODO..
//d := fdkaac.NewAacDecoder()
}
// Calculate the difference
//bufferDuration := pkt.Time - previousTimeAudio
//previousTimeAudio = pkt.Time
// We will send the audio
sample := pionMedia.Sample{Data: pkt.Data, Duration: pkt.Time}
//bufferDurationCasted := time.Duration(bufferDuration) * time.Millisecond
sample := pionMedia.Sample{Data: pkt.Data, PacketTimestamp: uint32(pkt.Time)}
if err := audioTrack.WriteSample(sample); err != nil && err != io.ErrClosedPipe {
log.Log.Error("webrtc.main.WriteToTrack(): something went wrong while writing sample: " + err.Error())
}

4
machinery/update-mod.sh Executable file
View File

@@ -0,0 +1,4 @@
export GOSUMDB=off
rm -rf go.*
go mod init github.com/kerberos-io/agent/machinery
go mod tidy

View File

@@ -1,7 +1,6 @@
{
"name": "agent-ui",
"version": "0.1.0",
"private": false,
"dependencies": {
"@giantmachines/redux-websocket": "^1.5.1",
"@kerberos-io/ui": "^1.76.0",

View File

@@ -80,6 +80,7 @@
"description_general": "Allgemeine Einstellungen für den Kerberos Agent",
"key": "Schlüssel",
"camera_name": "Kamera Name",
"camera_friendly_name": "Kamera Anzeigename",
"timezone": "Zeitzone",
"select_timezone": "Zeitzone auswählen",
"advanced_configuration": "Erweiterte Konfiguration",
@@ -145,6 +146,8 @@
"turn_server": "TURN Server",
"turn_username": "Benutzername",
"turn_password": "Passwort",
"force_turn": "Erzwinge TURN",
"force_turn_description": "Erzwinge die Verwendung von TURN",
"stun_turn_forward": "Weiterleiten und transkodieren",
"stun_turn_description_forward": "Optiemierungen und Verbesserungen der TURN/STUN Kommunikation.",
"stun_turn_webrtc": "Weiterleiten an WebRTC Schnittstelle",
@@ -185,6 +188,8 @@
"description_persistence": "Die möglichkeit zur Speicherung der Daten an einem Zentralen Ort ist der Beginn einer effektiven Videoüberwachung. Es kann zwischen",
"description2_persistence": ", oder einem Drittanbieter gewählt werden.",
"select_persistence": "Speicherort auswählen",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "Der Proxy Endpunkt zum hochladen der Aufnahmen.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -157,7 +160,12 @@
"description2_mqtt": "to the Kerberos Agent, to achieve for example livestreaming or ONVIF (PTZ) capabilities.",
"mqtt_brokeruri": "Broker Uri",
"mqtt_username": "Username",
"mqtt_password": "Password"
"mqtt_password": "Password",
"realtimeprocessing": "Realtime Processing",
"description_realtimeprocessing": "By enabling realtime processing, you will receive realtime video keyframes through the MQTT connection specified above.",
"realtimeprocessing_topic": "Topic to publish",
"realtimeprocessing_enabled": "Enable realtime processing",
"description_realtimeprocessing_enabled": "Send realtime video keyframes through MQTT."
},
"conditions": {
"timeofinterest": "Time Of Interest",
@@ -185,6 +193,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Camera friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -185,6 +188,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -79,6 +79,7 @@
"description_general": "Paramètres généraux pour votre Agent Kerberos",
"key": "Clé",
"camera_name": "Nom de la caméra",
"camera_friendly_name": "Nom convivial de la caméra",
"timezone": "Fuseau horaire",
"select_timezone": "Sélectionner un fuseau horaire",
"advanced_configuration": "Configuration avancée",
@@ -144,6 +145,8 @@
"turn_server": "Serveur TURN",
"turn_username": "Nom d'utilisateur",
"turn_password": "Mot de passe",
"force_turn": "Forcer l'utilisation de TURN",
"force_turn_description": "Forcer l'utilisation de TURN au lieu de STUN",
"stun_turn_forward": "Redirection et transcodage",
"stun_turn_description_forward": "Optimisations et améliorations pour la communication TURN/STUN.",
"stun_turn_webrtc": "Redirection pour l'agent WebRTC",
@@ -184,6 +187,8 @@
"description_persistence": "Avoir la possibilité de stocker vos enregistrements est le commencement de tout. Vous pouvez choisir entre notre",
"description2_persistence": " ou auprès d'un fournisseur tiers",
"select_persistence": "Sélectionner une persistance",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "URL du proxy Kerberos Hub",
"kerberoshub_description_proxyurl": "Le point de terminaison du proxy pour téléverser vos enregistrements.",
"kerberoshub_apiurl": "URL de l'API Kerberos Hub",

View File

@@ -80,6 +80,7 @@
"description_general": "आपके Kerberos एजेंट के लिए सामान्य सेटिंग्स",
"key": "की",
"camera_name": "कैमरे का नाम",
"camera_friendly_name": "कैमरे का नाम",
"timezone": "समय क्षेत्र",
"select_timezone": "समयक्षेत्र चुनें",
"advanced_configuration": "एडवांस कॉन्फ़िगरेशन",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "उपयोगकर्ता नाम",
"turn_password": "पासवर्ड",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "फोरवर्डींग और ट्रांसकोडिंग",
"stun_turn_description_forward": "TURN/STUN संचार के लिए अनुकूलन और संवर्द्धन।",
"stun_turn_webrtc": "WebRTC ब्रोकर को फोरवर्डींग किया जा रहा है",
@@ -185,6 +188,8 @@
"description_persistence": "अपनी रिकॉर्डिंग संग्रहीत करने की क्षमता होना हर चीज़ की शुरुआत है। ",
"description2_persistence": ", या कोई तृतीय पक्ष प्रदाता",
"select_persistence": "एक दृढ़ता का चयन करें",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos हब प्रॉक्सी URL",
"kerberoshub_description_proxyurl": "आपकी रिकॉर्डिंग अपलोड करने के लिए प्रॉक्सी एंडपॉइंट।",
"kerberoshub_apiurl": "Kerberos हब API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Impostazioni generali del Kerberos Agent",
"key": "Chiave",
"camera_name": "Nome videocamera",
"camera_friendly_name": "Nome amichevole videocamera",
"timezone": "Fuso orario",
"select_timezone": "Seleziona un fuso orario",
"advanced_configuration": "Configurazione avanzata",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Forza TURN",
"force_turn_description": "Forza l'uso di TURN per lo streaming in diretta.",
"stun_turn_forward": "Inoltro e transcodifica",
"stun_turn_description_forward": "Ottimizzazioni e miglioramenti per la comunicazione TURN/STUN.",
"stun_turn_webrtc": "Inoltro al broker WebRTC",
@@ -185,6 +188,8 @@
"description_persistence": "La possibilità di poter salvare le tue registrazioni rappresenta l'inizio di tutto. Puoi scegliere tra il nostro",
"description2_persistence": ", oppure un provider di terze parti",
"select_persistence": "Seleziona una persistenza",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "URL Proxy Kerberos Hub",
"kerberoshub_description_proxyurl": "Endpoint del Proxy per l'upload delle registrazioni.",
"kerberoshub_apiurl": "API URL Kerberos Hub",

View File

@@ -80,6 +80,7 @@
"description_general": "Kerberos エージェントの一般設定",
"key": "鍵",
"camera_name": "カメラ名",
"camera_friendly_name": "カメラのフレンドリー名",
"timezone": "タイムゾーン",
"select_timezone": "タイムゾーンを選択",
"advanced_configuration": "詳細設定",
@@ -145,6 +146,8 @@
"turn_server": "TURNサーバー",
"turn_username": "ユーザー名",
"turn_password": "パスワード",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "転送とトランスコーディング",
"stun_turn_description_forward": "TURN/STUN 通信の最適化と機能強化。",
"stun_turn_webrtc": "WebRTC ブローカーへの転送",
@@ -185,6 +188,8 @@
"description_persistence": "録音を保存する機能を持つことは、すべての始まりです。",
"description2_persistence": "、またはサードパーティのプロバイダ",
"select_persistence": "永続性を選択",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos ハブ プロキシ URL",
"kerberoshub_description_proxyurl": "記録をアップロードするためのプロキシ エンドポイント。",
"kerberoshub_apiurl": "ケルベロス ハブ API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Algemene instellingen voor jouw Kerberos Agent",
"key": "Key",
"camera_name": "Camera naam",
"camera_friendly_name": "Camera vriendelijke naam",
"timezone": "Tijdzone",
"select_timezone": "Selecteer uw tijdzone",
"advanced_configuration": "Geavanceerde instellingen",
@@ -146,6 +147,8 @@
"turn_server": "TURN server",
"turn_username": "Gebruikersnaam",
"turn_password": "Wachtwoord",
"force_turn": "Verplicht TURN",
"force_turn_description": "Verplicht TURN connectie, ook al is er een STUN connectie mogelijk.",
"stun_turn_forward": "Doorsturen en transcoden",
"stun_turn_description_forward": "Optimalisatie en verbetering voor TURN/STUN communicatie.",
"stun_turn_webrtc": "Doorsturen naar een WebRTC broker",
@@ -186,6 +189,8 @@
"description_persistence": "De mogelijkheid om jouw opnames op te slaan is het begin van alles. Je kan kiezen tussen ons",
"description2_persistence": ", of een 3rd party provider",
"select_persistence": "Selecteer een opslagmethode",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "De Proxy url voor het opladen van jouw opnames.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Camera friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -185,6 +188,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Configurações gerais para seu agente Kerberos",
"key": "Chave",
"camera_name": "Nome da câmera",
"camera_friendly_name": "Nome amigável da câmera",
"timezone": "Fuso horário",
"select_timezone": "Selecione a timezone",
"advanced_configuration": "Configurações avançadas",
@@ -145,6 +146,8 @@
"turn_server": "Servidor TURN",
"turn_username": "Usuario",
"turn_password": "Senha",
"force_turn": "Forçar TURN",
"force_turn_description": "Forçar o uso de TURN em vez de STUN.",
"stun_turn_forward": "Encaminhamento e transcodificação",
"stun_turn_description_forward": "Otimizações e melhorias para a comunicação TURN/STUN.",
"stun_turn_webrtc": "Encaminhamento para broker WebRTC",
@@ -185,6 +188,8 @@
"description_persistence": "Ter a capacidade de armazenar suas gravações é o começo de tudo. Você pode escolher entre nossos",
"description2_persistence": ", ou um provedor terceirizado",
"select_persistence": "Selecione um provedor de armazenamento",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Url proxy para Kerberos Hub",
"kerberoshub_description_proxyurl": "O endpoint Proxy para enviar suas gravações.",
"kerberoshub_apiurl": "Url de API do Kerberos Hub",

View File

@@ -0,0 +1,234 @@
{
"breadcrumb": {
"watch_recordings": "Vizionează înregistrări",
"configure": "Configurează"
},
"buttons": {
"save": "Salvează",
"verify_connection": "Verifică conexiunea"
},
"navigation": {
"profile": "Profil",
"admin": "admin",
"management": "Management",
"dashboard": "Tablou de bord",
"recordings": "Înregistrări",
"settings": "Setări",
"help_support": "Ajutor & Suport",
"swagger": "Swagger API",
"documentation": "Documentație",
"ui_library": "Bibliotecă UI",
"layout": "Limbă și aspect",
"choose_language": "Alege limba"
},
"dashboard": {
"title": "Tablou de bord",
"heading": "Prezentare generală a supravegherii video",
"number_of_days": "Număr de zile",
"total_recordings": "Înregistrări totale",
"connected": "Conectat",
"not_connected": "Neconectat",
"offline_mode": "Mod offline",
"latest_events": "Evenimente recente",
"configure_connection": "Configurează conexiunea",
"no_events": "Niciun eveniment",
"no_events_description": "Nu au fost găsite înregistrări, asigurați-vă că agentul dvs. Kerberos este configurat corect.",
"motion_detected": "Mișcare detectată",
"live_view": "Vizualizare live",
"loading_live_view": "Se încarcă vizualizarea live",
"loading_live_view_description": "Așteptați, încărcăm vizualizarea dvs. live. Dacă nu ați configurat conexiunea camerei, actualizați-o în paginile de setări.",
"time": "Timp",
"description": "Descriere",
"name": "Nume"
},
"recordings": {
"title": "Înregistrări",
"heading": "Toate înregistrările tale într-un singur loc",
"search_media": "Caută media"
},
"settings": {
"title": "Setări",
"heading": "Prezentare generală a setărilor camerei și agentului",
"submenu": {
"all": "Toate",
"overview": "General",
"camera": "Camera",
"recording": "Înregistrare",
"streaming": "Streaming",
"conditions": "Condiții",
"persistence": "Persistență"
},
"info": {
"kerberos_hub_demo": "Aruncă o privire asupra mediului nostru de demonstrație Kerberos Hub, pentru a vedea Kerberos Hub în acțiune!",
"configuration_updated_success": "Configurarea ta a fost actualizată cu succes.",
"configuration_updated_error": "Ceva a mers prost în timpul salvării.",
"verify_hub": "Verificarea setărilor tale Kerberos Hub.",
"verify_hub_success": "Setările Kerberos Hub au fost verificate cu succes.",
"verify_hub_error": "Ceva a mers prost în timpul verificării Kerberos Hub.",
"verify_persistence": "Verificarea setărilor tale de persistență.",
"verify_persistence_success": "Setările de persistență au fost verificate cu succes.",
"verify_persistence_error": "Ceva a mers prost în timpul verificării persistenței.",
"verify_camera": "Verificarea setărilor tale pentru cameră.",
"verify_camera_success": "Setările pentru cameră au fost verificate cu succes.",
"verify_camera_error": "Ceva a mers prost în timpul verificării setărilor pentru cameră.",
"verify_onvif": "Verificarea setărilor tale ONVIF.",
"verify_onvif_success": "Setările ONVIF au fost verificate cu succes.",
"verify_onvif_error": "Ceva a mers prost în timpul verificării setărilor ONVIF."
},
"overview": {
"general": "General",
"description_general": "Setări generale pentru Agentul tău Kerberos",
"key": "Cheie",
"camera_name": "Numele camerei",
"camera_friendly_name": "Nume prietenos",
"timezone": "Fus orar",
"select_timezone": "Selectează un fus orar",
"advanced_configuration": "Configurare avansată",
"description_advanced_configuration": "Opțiuni detaliate de configurare pentru activarea sau dezactivarea anumitor părți ale Agentului Kerberos",
"offline_mode": "Mod offline",
"description_offline_mode": "Dezactivează tot traficul ieșit",
"encryption": "Criptare",
"description_encryption": "Activează criptarea pentru tot traficul ieșit. Mesajele MQTT și/sau înregistrările vor fi criptate folosind AES-256. O cheie privată este utilizată pentru semnare.",
"encryption_enabled": "Activează criptarea MQTT",
"description_encryption_enabled": "Activează criptarea pentru toate mesajele MQTT.",
"encryption_recordings_enabled": "Activează criptarea înregistrărilor",
"description_encryption_recordings_enabled": "Activează criptarea pentru toate înregistrările.",
"encryption_fingerprint": "Amprentă",
"encryption_privatekey": "Cheie privată",
"encryption_symmetrickey": "Cheie simetrică"
},
"camera": {
"camera": "Camera",
"description_camera": "Setările camerei sunt necesare pentru a face o conexiune cu camera aleasă de tine.",
"only_h264": "În prezent sunt suportate doar fluxurile RTSP H264/H265.",
"rtsp_url": "URL RTSP",
"rtsp_h264": "O conexiune RTSP H264/H265 la camera ta.",
"sub_rtsp_url": "URL RTSP secundar (folosit pentru transmisie live)",
"sub_rtsp_h264": "O conexiune RTSP secundară la rezoluția redusă a camerei tale.",
"onvif": "ONVIF",
"description_onvif": "Credențiale pentru comunicarea cu capabilitățile ONVIF. Acestea sunt folosite pentru funcții PTZ sau alte capabilități oferite de cameră.",
"onvif_xaddr": "Adresă ONVIF",
"onvif_username": "Nume utilizator ONVIF",
"onvif_password": "Parolă ONVIF",
"verify_connection": "Verifică conexiunea",
"verify_sub_connection": "Verifică conexiunea secundară"
},
"recording": {
"recording": "Înregistrare",
"description_recording": "Specificați cum doriți să realizați înregistrări. Puteți avea o configurație continuă 24/7 sau înregistrări bazate pe mișcare.",
"continuous_recording": "Înregistrare continuă",
"description_continuous_recording": "Realizați înregistrări 24/7 sau bazate pe mișcare.",
"max_duration": "durata maximă a videoclipului (secunde)",
"description_max_duration": "Durata maximă a unei înregistrări.",
"pre_recording": "pre-înregistrare (cadre cheie tamponate)",
"description_pre_recording": "Secunde înainte de producerea unui eveniment.",
"post_recording": "post-înregistrare (secunde)",
"description_post_recording": "Secunde după producerea unui eveniment.",
"threshold": "Prag de înregistrare (pixeli)",
"description_threshold": "Numărul de pixeli modificați pentru a înregistra.",
"autoclean": "Curățare automată",
"description_autoclean": "Specificați dacă Agentul Kerberos poate curăța automat înregistrările când se atinge o anumită capacitate de stocare (MB). Se vor șterge cele mai vechi înregistrări când se atinge capacitatea specificată.",
"autoclean_enable": "Activează curățarea automată",
"autoclean_description_enable": "Șterge cele mai vechi înregistrări când capacitatea este atinsă.",
"autoclean_max_directory_size": "Dimensiunea maximă a directorului (MB)",
"autoclean_description_max_directory_size": "Maximum de MB stocați în înregistrări.",
"fragmentedrecordings": "Înregistrări fragmentate",
"description_fragmentedrecordings": "Când înregistrările sunt fragmentate, sunt potrivite pentru un flux HLS. Când este activat, containerul MP4 va arăta puțin diferit.",
"fragmentedrecordings_enable": "Activează fragmentarea",
"fragmentedrecordings_description_enable": "Înregistrările fragmentate sunt necesare pentru HLS.",
"fragmentedrecordings_duration": "durata fragmentului",
"fragmentedrecordings_description_duration": "Durata unui singur fragment."
},
"streaming": {
"stun_turn": "STUN/TURN pentru WebRTC",
"description_stun_turn": "Pentru transmisii live la rezoluție completă folosim conceptul WebRTC. Una dintre capabilitățile cheie este funcționalitatea ICE-candidate, care permite traversarea NAT folosind conceptele STUN/TURN.",
"stun_server": "Server STUN",
"turn_server": "Server TURN",
"turn_username": "Nume utilizator",
"turn_password": "Parolă",
"force_turn": "Forțează TURN",
"force_turn_description": "Utilizează TURN în mod forțat, chiar și atunci când STUN este disponibil.",
"stun_turn_forward": "Redirecționare și transcodare",
"stun_turn_description_forward": "Optimizări și îmbunătățiri pentru comunicarea TURN/STUN.",
"stun_turn_webrtc": "Redirecționare către broker WebRTC",
"stun_turn_description_webrtc": "Redirecționare flux h264 prin MQTT",
"stun_turn_transcode": "Transcodare flux",
"stun_turn_description_transcode": "Convertire flux la o rezoluție mai mică",
"stun_turn_downscale": "Scădere rezoluție (în % din rezoluția originală)",
"mqtt": "MQTT",
"description_mqtt": "Un broker MQTT este utilizat pentru comunicare de la",
"description2_mqtt": "către Agentul Kerberos, pentru a realiza, de exemplu, transmisiuni live sau capabilități ONVIF (PTZ).",
"mqtt_brokeruri": "URI broker MQTT",
"mqtt_username": "Nume utilizator",
"mqtt_password": "Parolă",
"realtimeprocessing": "Procesare în timp real",
"description_realtimeprocessing": "Prin activarea procesării în timp real, veți primi cadre cheie video în timp real prin conexiunea MQTT specificată mai sus.",
"realtimeprocessing_topic": "Topic pentru publicare",
"realtimeprocessing_enabled": "Activează procesarea în timp real",
"description_realtimeprocessing_enabled": "Trimite cadre video în timp real prin MQTT."
},
"conditions": {
"timeofinterest": "Timpul de Interes",
"description_timeofinterest": "Realizează înregistrări doar între intervale de timp specifice (bazate pe fusul orar).",
"timeofinterest_enabled": "Activat",
"timeofinterest_description_enabled": "Dacă este activat, puteți specifica intervale de timp",
"sunday": "Duminică",
"monday": "Luni",
"tuesday": "Marți",
"wednesday": "Miercuri",
"thursday": "Joi",
"friday": "Vineri",
"saturday": "Sâmbătă",
"externalcondition": "Condiție Externă",
"description_externalcondition": "În funcție de un serviciu web extern, înregistrarea poate fi activată sau dezactivată.",
"regionofinterest": "Regiunea de Interes",
"description_regionofinterest": "Prin definirea unei sau mai multor regiuni, mișcarea va fi urmărită doar în regiunile pe care le-ați definit."
},
"persistence": {
"kerberoshub": "Kerberos Hub",
"description_kerberoshub": "Agenta Kerberos poate trimite semnale de puls către o",
"description2_kerberoshub": "instalație centrală. Semnalele de puls și alte informații relevante sunt sincronizate cu Kerberos Hub pentru a afișa informații în timp real despre peisajul video.",
"persistence": "Persistență",
"saasoffering": "Kerberos Hub (ofertă SAAS)",
"description_persistence": "Capacitatea de a stoca înregistrările este începutul fiecărei",
"description2_persistence": ", sau de la un furnizor terț",
"select_persistence": "Selectați o persistență",
"kerberoshub_encryption": "Criptare",
"kerberoshub_encryption_description": "Tot traficul de la/spre Kerberos Hub va fi criptat folosind AES-256.",
"kerberoshub_proxyurl": "URL Proxy Kerberos Hub",
"kerberoshub_description_proxyurl": "Punctul final Proxy pentru încărcarea înregistrărilor tale.",
"kerberoshub_apiurl": "URL API Kerberos Hub",
"kerberoshub_description_apiurl": "Punctul final API pentru încărcarea înregistrărilor tale.",
"kerberoshub_publickey": "Cheie publică",
"kerberoshub_description_publickey": "Cheia publică acordată contului tău Kerberos Hub.",
"kerberoshub_privatekey": "Cheie privată",
"kerberoshub_description_privatekey": "Cheia privată acordată contului tău Kerberos Hub.",
"kerberoshub_site": "Site",
"kerberoshub_description_site": "ID-ul site-ului la care aparțin Agenta Kerberos în Kerberos Hub.",
"kerberoshub_region": "Regiune",
"kerberoshub_description_region": "Regiunea în care sunt stocate înregistrările noastre.",
"kerberoshub_bucket": "Bucket",
"kerberoshub_description_bucket": "Bucket-ul în care sunt stocate înregistrările noastre.",
"kerberoshub_username": "Nume utilizator/Director (trebuie să se potrivească cu numele de utilizator Kerberos Hub)",
"kerberoshub_description_username": "Numele de utilizator al contului tău Kerberos Hub.",
"kerberosvault_apiurl": "URL API Kerberos Vault",
"kerberosvault_description_apiurl": "API-ul Kerberos Vault",
"kerberosvault_provider": "Furnizor",
"kerberosvault_description_provider": "Furnizorul către care vor fi trimise înregistrările tale.",
"kerberosvault_directory": "Director (trebuie să se potrivească cu numele de utilizator Kerberos Hub)",
"kerberosvault_description_directory": "Subdirectorul în care vor fi stocate înregistrările la furnizorul tău.",
"kerberosvault_accesskey": "Cheie de acces",
"kerberosvault_description_accesskey": "Cheia de acces a contului tău Kerberos Vault.",
"kerberosvault_secretkey": "Cheie secretă",
"kerberosvault_description_secretkey": "Cheia secretă a contului tău Kerberos Vault.",
"dropbox_directory": "Director",
"dropbox_description_directory": "Subdirectorul în care vor fi stocate înregistrările în contul tău Dropbox.",
"dropbox_accesstoken": "Token de acces",
"dropbox_description_accesstoken": "Tokenul de acces al contului/aplicației tale Dropbox.",
"verify_connection": "Verifică conexiunea",
"remove_after_upload": "Odată ce înregistrările sunt încărcate într-o persistență, este posibil să doriți să le ștergeți de pe Agenta Kerberos locală.",
"remove_after_upload_description": "Ștergeți înregistrările după ce sunt încărcate cu succes.",
"remove_after_upload_enabled": "Ștergere activată la încărcare"
}
}
}

View File

@@ -80,6 +80,7 @@
"description_general": "Общие настройки Kerberos Agent",
"key": "Ключ",
"camera_name": "Название камеры",
"camera_friendly_name": "Дружественное название камеры",
"timezone": "Часовой пояс",
"select_timezone": "Выберите часовой пояс",
"advanced_configuration": "Расширенные настройки",
@@ -145,6 +146,8 @@
"turn_server": "TURN сервер",
"turn_username": "Имя пользователя",
"turn_password": "Пароль",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Переадресация и транскодирование",
"stun_turn_description_forward": "Оптимизация и усовершенствование связи TURN/STUN.",
"stun_turn_webrtc": "Переадресация на WebRTC-брокера",
@@ -185,6 +188,8 @@
"description_persistence": "Возможность хранения записей - это начало всего. Вы можете выбрать один из наших вариантов",
"description2_persistence": ", или стороннего провайдера",
"select_persistence": "Выберите хранилище",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "Конечная точка Proxy для загрузки записей.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Kerberos Agent 常规设置",
"key": "Key",
"camera_name": "相机名称",
"camera_friendly_name": "相机友好名称",
"timezone": "时区",
"select_timezone": "选择时区",
"advanced_configuration": "高级配置",
@@ -145,6 +146,8 @@
"turn_server": "TURN 服务",
"turn_username": "账户",
"turn_password": "密码",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "转发和转码",
"stun_turn_description_forward": "TURN/STUN 通信的优化和增强。",
"stun_turn_webrtc": "转发到 WebRTC 代理",
@@ -185,6 +188,8 @@
"description_persistence": "能够存储您的录像是一切的开始。您可以在我们的",
"description2_persistence": ", 或第三方提供商之间进行选择。",
"select_persistence": "选择持久化存储",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub 代理 URL",
"kerberoshub_description_proxyurl": "用于上传您录像的代理端点",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -100,7 +100,7 @@ class App extends React.Component {
</div>
)}
<div id="page-root">
<Sidebar logo={logo} title="Kerberos Agent" version="v3.1.1" mobile>
<Sidebar logo={logo} title="Kerberos Agent" version="v3.1.8" mobile>
<Profilebar
username={username}
email="support@kerberos.io"

View File

@@ -26,6 +26,7 @@ const LanguageSelect = () => {
ja: { label: '日本', dir: 'rlt', active: false },
hi: { label: 'हिंदी', dir: 'ltr', active: false },
ru: { label: 'Русский', dir: 'ltr', active: false },
ro: { label: 'Română', dir: 'ltr', active: false },
};
if (!languageMap[selected]) {

View File

@@ -14,7 +14,7 @@ i18n
escapeValue: false,
},
load: 'languageOnly',
whitelist: ['de', 'en', 'nl', 'fr', 'pl', 'es', 'pt', 'ja', 'ru'],
whitelist: ['de', 'en', 'nl', 'fr', 'pl', 'es', 'pt', 'ja', 'ru', 'ro'],
});
export default i18n;

View File

@@ -824,6 +824,15 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
label={t('settings.overview.camera_friendly_name')}
defaultValue={config.friendly_name}
onChange={(value) =>
this.onUpdateField('', 'friendly_name', value, config)
}
/>
<Dropdown
isRadio
icon="world"
@@ -1088,6 +1097,101 @@ class Settings extends React.Component {
this.onUpdateField('', 'turn_password', value, config)
}
/>
<br />
<div className="toggle-wrapper">
<Toggle
on={config.turn_force === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle('', 'turn_force', event, config)
}
/>
<div>
<span>{t('settings.streaming.force_turn')}</span>
<p>{t('settings.streaming.force_turn_description')}</p>
</div>
</div>
</BlockBody>
<BlockFooter>
<Button
label={t('buttons.save')}
onClick={this.saveConfig}
type="default"
icon="pencil"
/>
</BlockFooter>
</Block>
)}
{/* STUN/TURN block */}
{showStreamingSection && config.offline !== 'true' && (
<Block>
<BlockHeader>
<h4>{t('settings.streaming.stun_turn_forward')}</h4>
</BlockHeader>
<BlockBody>
<p>{t('settings.streaming.stun_turn_description_forward')}</p>
<div className="toggle-wrapper">
<Toggle
on={config.capture.forwardwebrtc === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle(
'capture',
'forwardwebrtc',
event,
config.capture
)
}
/>
<div>
<span>{t('settings.streaming.stun_turn_webrtc')}</span>
<p>
{t('settings.streaming.stun_turn_description_webrtc')}
</p>
</div>
</div>
<div className="toggle-wrapper">
<Toggle
on={config.capture.transcodingwebrtc === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle(
'capture',
'transcodingwebrtc',
event,
config.capture
)
}
/>
<div>
<span>{t('settings.streaming.stun_turn_transcode')}</span>
<p>
{t(
'settings.streaming.stun_turn_description_transcode'
)}
</p>
</div>
</div>
{config.capture.transcodingwebrtc === 'true' && (
<Input
noPadding
label={t('settings.streaming.stun_turn_downscale')}
value={config.capture.transcodingresolution}
placeholder="The % of the original resolution."
onChange={(value) =>
this.onUpdateNumberField(
'capture',
'transcodingresolution',
value,
config.capture
)
}
/>
)}
</BlockBody>
<BlockFooter>
<Button
@@ -1129,7 +1233,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.persistence.kerberoshub_publickey')}
placeholder={t(
'settings.persistence.kerberoshub_description_publickey'
@@ -1140,7 +1245,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.persistence.kerberoshub_privatekey')}
placeholder={t(
'settings.persistence.kerberoshub_description_privatekey'
@@ -1161,6 +1267,27 @@ class Settings extends React.Component {
this.onUpdateField('', 'hub_site', value, config)
}
/>
<br />
<div className="toggle-wrapper">
<Toggle
on={config.hub_encryption === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle('', 'hub_encryption', event, config)
}
/>
<div>
<span>
{t('settings.persistence.kerberoshub_encryption')}
</span>
<p>
{t(
'settings.persistence.kerberoshub_encryption_description'
)}
</p>
</div>
</div>
</BlockBody>
<BlockFooter>
<Button
@@ -1336,7 +1463,8 @@ class Settings extends React.Component {
</div>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_fingerprint')}
value={config.encryption.fingerprint}
onChange={(value) =>
@@ -1349,7 +1477,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_privatekey')}
value={config.encryption.private_key}
onChange={(value) =>
@@ -1362,7 +1491,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_symmetrickey')}
value={config.encryption.symmetric_key}
onChange={(value) =>
@@ -1439,75 +1569,55 @@ class Settings extends React.Component {
</Block>
)}
{/* STUN/TURN block */}
{showStreamingSection && config.offline !== 'true' && (
<Block>
<BlockHeader>
<h4>{t('settings.streaming.stun_turn_forward')}</h4>
<h4>{t('settings.streaming.realtimeprocessing')}</h4>
</BlockHeader>
<BlockBody>
<p>{t('settings.streaming.stun_turn_description_forward')}</p>
<p>
{t('settings.streaming.description_realtimeprocessing')}
</p>
<div className="toggle-wrapper">
<Toggle
on={config.capture.forwardwebrtc === 'true'}
on={config.realtimeprocessing === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle(
'capture',
'forwardwebrtc',
'',
'realtimeprocessing',
event,
config.capture
config
)
}
/>
<div>
<span>{t('settings.streaming.stun_turn_webrtc')}</span>
<p>
{t('settings.streaming.stun_turn_description_webrtc')}
</p>
</div>
</div>
<div className="toggle-wrapper">
<Toggle
on={config.capture.transcodingwebrtc === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle(
'capture',
'transcodingwebrtc',
event,
config.capture
)
}
/>
<div>
<span>{t('settings.streaming.stun_turn_transcode')}</span>
<span>
{t('settings.streaming.realtimeprocessing_enabled')}
</span>
<p>
{t(
'settings.streaming.stun_turn_description_transcode'
'settings.streaming.description_realtimeprocessing_enabled'
)}
</p>
</div>
</div>
{config.capture.transcodingwebrtc === 'true' && (
<Input
noPadding
label={t('settings.streaming.stun_turn_downscale')}
value={config.capture.transcodingresolution}
placeholder="The % of the original resolution."
onChange={(value) =>
this.onUpdateNumberField(
'capture',
'transcodingresolution',
value,
config.capture
)
}
/>
)}
<Input
noPadding
label={t('settings.streaming.realtimeprocessing_topic')}
value={config.realtimeprocessing_topic}
placeholder="kerberos/keyframes/key"
onChange={(value) =>
this.onUpdateField(
'',
'realtimeprocessing_topic',
value,
config
)
}
/>
</BlockBody>
<BlockFooter>
<Button
@@ -2296,7 +2406,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t(
'settings.persistence.kerberosvault_accesskey'
)}
@@ -2316,7 +2427,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t(
'settings.persistence.kerberosvault_secretkey'
)}