From 143f76d7af134adc8bde4d32d1d37f2c3c198a92 Mon Sep 17 00:00:00 2001 From: Erik Jaegervall Date: Mon, 29 Apr 2024 11:29:06 +0200 Subject: [PATCH] Removing databroker --- .../workflows/kuksa_databroker-cli_build.yml | 178 - .github/workflows/kuksa_databroker_build.yml | 248 -- Cargo.lock | 3622 ----------------- Cargo.toml | 49 - Cross.toml | 15 - README.md | 7 +- jwt/README.md | 22 - jwt/actuate-provide-all.json | 10 - jwt/actuate-provide-all.token | 1 - jwt/provide-all.json | 10 - jwt/provide-all.token | 1 - jwt/provide-vehicle-speed.json | 10 - jwt/provide-vehicle-speed.token | 1 - jwt/read-all.json | 10 - jwt/read-all.token | 1 - jwt/read-vehicle-speed.json | 10 - jwt/read-vehicle-speed.token | 1 - kuksa_databroker/.dockerignore | 1 - kuksa_databroker/.gitignore | 1 - kuksa_databroker/DEPENDENCIES | 134 - kuksa_databroker/Dockerfile | 58 - kuksa_databroker/Dockerfile-cli | 58 - kuksa_databroker/NOTICE.md | 189 - kuksa_databroker/README.md | 267 -- kuksa_databroker/build-all-targets-cli.sh | 80 - kuksa_databroker/build-all-targets.sh | 79 - kuksa_databroker/createbom/README.md | 20 - .../createbom/bomutil/maplicensefile.py | 40 - kuksa_databroker/createbom/bomutil/quirks.py | 36 - kuksa_databroker/createbom/createbom.py | 201 - .../createbom/licensestore/0BSD.txt.gz | Bin 401 -> 0 bytes .../createbom/licensestore/Apache-2.0.txt.gz | Bin 3977 -> 0 bytes .../licensestore/BSD-2-Clause.txt.gz | Bin 721 -> 0 bytes .../licensestore/BSD-3-Clause.txt.gz | Bin 37 -> 0 bytes .../createbom/licensestore/BSL-1.0.txt.gz | Bin 781 -> 0 bytes .../licensestore/BlueOak-1.0.0.md.gz | Bin 758 -> 0 bytes .../createbom/licensestore/CC0-1.0.txt.gz | Bin 2838 -> 0 bytes .../createbom/licensestore/ISC.txt.gz | Bin 459 -> 0 bytes .../createbom/licensestore/MIT.txt.gz | Bin 651 -> 0 bytes .../licensestore/Unicode-DFS-2016.txt.gz | Bin 1219 -> 0 bytes .../createbom/licensestore/Unlicense.txt.gz | Bin 723 -> 0 bytes .../createbom/licensestore/WTFPL.txt.gz | Bin 314 -> 0 bytes .../createbom/licensestore/Zlib.txt.gz | Bin 488 -> 0 bytes .../licensestore/ring.LICENSE.txt.gz | Bin 3341 -> 0 bytes .../licensestore/webpki.LICENSE.txt.gz | Bin 595 -> 0 bytes kuksa_databroker/databroker-cli/Cargo.toml | 48 - kuksa_databroker/databroker-cli/src/cli.rs | 391 -- .../databroker-cli/src/kuksa_cli.rs | 1299 ------ kuksa_databroker/databroker-cli/src/main.rs | 41 - .../databroker-cli/src/sdv_cli.rs | 1333 ------ kuksa_databroker/databroker-proto/Cargo.toml | 28 - kuksa_databroker/databroker-proto/build.rs | 30 - kuksa_databroker/databroker-proto/proto | 1 - kuksa_databroker/databroker-proto/src/lib.rs | 147 - kuksa_databroker/databroker/Cargo.toml | 92 - kuksa_databroker/databroker/Cross.toml | 4 - kuksa_databroker/databroker/build.rs | 22 - .../src/authorization/jwt/decoder.rs | 211 - .../databroker/src/authorization/jwt/mod.rs | 17 - .../databroker/src/authorization/jwt/scope.rs | 282 -- .../databroker/src/authorization/mod.rs | 37 - kuksa_databroker/databroker/src/broker.rs | 3147 -------------- kuksa_databroker/databroker/src/glob.rs | 1544 ------- .../src/grpc/kuksa_val_v1/conversions.rs | 340 -- .../databroker/src/grpc/kuksa_val_v1/mod.rs | 15 - .../databroker/src/grpc/kuksa_val_v1/val.rs | 746 ---- kuksa_databroker/databroker/src/grpc/mod.rs | 17 - .../src/grpc/sdv_databroker_v1/broker.rs | 244 -- .../src/grpc/sdv_databroker_v1/collector.rs | 266 -- .../src/grpc/sdv_databroker_v1/conversions.rs | 330 -- .../src/grpc/sdv_databroker_v1/mod.rs | 16 - .../databroker/src/grpc/server.rs | 189 - kuksa_databroker/databroker/src/lib.rs | 44 - kuksa_databroker/databroker/src/main.rs | 455 --- .../databroker/src/permissions.rs | 295 -- .../databroker/src/query/compiler.rs | 548 --- .../databroker/src/query/executor.rs | 647 --- kuksa_databroker/databroker/src/query/expr.rs | 110 - kuksa_databroker/databroker/src/query/mod.rs | 25 - kuksa_databroker/databroker/src/types.rs | 1142 ------ kuksa_databroker/databroker/src/viss/mod.rs | 15 - .../databroker/src/viss/server.rs | 276 -- .../databroker/src/viss/v2/conversions.rs | 432 -- .../databroker/src/viss/v2/mod.rs | 19 - .../databroker/src/viss/v2/server.rs | 438 -- .../databroker/src/viss/v2/types.rs | 553 --- kuksa_databroker/databroker/src/vss.rs | 657 --- .../tests/features/read_write_values.feature | 180 - .../databroker/tests/read_write_values.rs | 281 -- .../databroker/tests/world/mod.rs | 401 -- kuksa_databroker/doc/QUERY.md | 266 -- kuksa_databroker/doc/TYPES.md | 40 - kuksa_databroker/doc/behavior.md | 4 - kuksa_databroker/doc/user_guide.md | 263 -- .../gen_proto/sdv/databroker/v1/broker_pb2.py | 114 - .../sdv/databroker/v1/broker_pb2.pyi | 144 - .../sdv/databroker/v1/broker_pb2_grpc.py | 146 - .../sdv/databroker/v1/collector_pb2.py | 163 - .../sdv/databroker/v1/collector_pb2.pyi | 184 - .../sdv/databroker/v1/collector_pb2_grpc.py | 166 - .../gen_proto/sdv/databroker/v1/types_pb2.py | 175 - .../gen_proto/sdv/databroker/v1/types_pb2.pyi | 375 -- .../sdv/databroker/v1/types_pb2_grpc.py | 4 - kuksa_databroker/integration_test/helper.py | 403 -- .../integration_test/requirements-dev.txt | 3 - .../integration_test/requirements.txt | 6 - kuksa_databroker/integration_test/run.sh | 42 - .../integration_test/test_databroker.py | 154 - .../integration_test/update-proto.sh | 52 - kuksa_databroker/lib/Cargo.lock | 1287 ------ kuksa_databroker/lib/Cargo.toml | 21 - kuksa_databroker/lib/common/Cargo.toml | 37 - kuksa_databroker/lib/common/src/lib.rs | 236 -- .../examples/perf_setter.rs | 216 - .../examples/perf_subscriber.rs | 122 - .../lib/databroker-examples/src/lib.rs | 12 - kuksa_databroker/lib/kuksa/Cargo.toml | 38 - kuksa_databroker/lib/kuksa/src/lib.rs | 356 -- kuksa_databroker/lib/sdv/Cargo.toml | 38 - kuksa_databroker/lib/sdv/src/lib.rs | 119 - kuksa_databroker/prepare_release.sh | 41 - kuksa_databroker/proto/kuksa/val/v1/README.md | 1 - .../proto/kuksa/val/v1/types.proto | 1 - kuksa_databroker/proto/kuksa/val/v1/val.proto | 1 - .../proto/sdv/databroker/v1/README.md | 12 - .../proto/sdv/databroker/v1/broker.proto | 96 - .../proto/sdv/databroker/v1/collector.proto | 97 - .../proto/sdv/databroker/v1/types.proto | 158 - proto/kuksa/val/v1/README.md | 6 - proto/kuksa/val/v1/types.proto | 288 -- proto/kuksa/val/v1/val.proto | 115 - 131 files changed, 3 insertions(+), 28714 deletions(-) delete mode 100644 .github/workflows/kuksa_databroker-cli_build.yml delete mode 100644 .github/workflows/kuksa_databroker_build.yml delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml delete mode 100644 Cross.toml delete mode 100644 jwt/README.md delete mode 100644 jwt/actuate-provide-all.json delete mode 100644 jwt/actuate-provide-all.token delete mode 100644 jwt/provide-all.json delete mode 100644 jwt/provide-all.token delete mode 100644 jwt/provide-vehicle-speed.json delete mode 100644 jwt/provide-vehicle-speed.token delete mode 100644 jwt/read-all.json delete mode 100644 jwt/read-all.token delete mode 100644 jwt/read-vehicle-speed.json delete mode 100644 jwt/read-vehicle-speed.token delete mode 100644 kuksa_databroker/.dockerignore delete mode 100644 kuksa_databroker/.gitignore delete mode 100644 kuksa_databroker/DEPENDENCIES delete mode 100644 kuksa_databroker/Dockerfile delete mode 100644 kuksa_databroker/Dockerfile-cli delete mode 100644 kuksa_databroker/NOTICE.md delete mode 100644 kuksa_databroker/README.md delete mode 100755 kuksa_databroker/build-all-targets-cli.sh delete mode 100755 kuksa_databroker/build-all-targets.sh delete mode 100644 kuksa_databroker/createbom/README.md delete mode 100644 kuksa_databroker/createbom/bomutil/maplicensefile.py delete mode 100644 kuksa_databroker/createbom/bomutil/quirks.py delete mode 100644 kuksa_databroker/createbom/createbom.py delete mode 100644 kuksa_databroker/createbom/licensestore/0BSD.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/Apache-2.0.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/BSD-2-Clause.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/BSD-3-Clause.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/BSL-1.0.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/BlueOak-1.0.0.md.gz delete mode 100644 kuksa_databroker/createbom/licensestore/CC0-1.0.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/ISC.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/MIT.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/Unicode-DFS-2016.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/Unlicense.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/WTFPL.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/Zlib.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/ring.LICENSE.txt.gz delete mode 100644 kuksa_databroker/createbom/licensestore/webpki.LICENSE.txt.gz delete mode 100644 kuksa_databroker/databroker-cli/Cargo.toml delete mode 100644 kuksa_databroker/databroker-cli/src/cli.rs delete mode 100644 kuksa_databroker/databroker-cli/src/kuksa_cli.rs delete mode 100644 kuksa_databroker/databroker-cli/src/main.rs delete mode 100644 kuksa_databroker/databroker-cli/src/sdv_cli.rs delete mode 100644 kuksa_databroker/databroker-proto/Cargo.toml delete mode 100644 kuksa_databroker/databroker-proto/build.rs delete mode 120000 kuksa_databroker/databroker-proto/proto delete mode 100644 kuksa_databroker/databroker-proto/src/lib.rs delete mode 100644 kuksa_databroker/databroker/Cargo.toml delete mode 100644 kuksa_databroker/databroker/Cross.toml delete mode 100644 kuksa_databroker/databroker/build.rs delete mode 100644 kuksa_databroker/databroker/src/authorization/jwt/decoder.rs delete mode 100644 kuksa_databroker/databroker/src/authorization/jwt/mod.rs delete mode 100644 kuksa_databroker/databroker/src/authorization/jwt/scope.rs delete mode 100644 kuksa_databroker/databroker/src/authorization/mod.rs delete mode 100644 kuksa_databroker/databroker/src/broker.rs delete mode 100644 kuksa_databroker/databroker/src/glob.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/kuksa_val_v1/conversions.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/kuksa_val_v1/mod.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/mod.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/collector.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/conversions.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/mod.rs delete mode 100644 kuksa_databroker/databroker/src/grpc/server.rs delete mode 100644 kuksa_databroker/databroker/src/lib.rs delete mode 100644 kuksa_databroker/databroker/src/main.rs delete mode 100644 kuksa_databroker/databroker/src/permissions.rs delete mode 100644 kuksa_databroker/databroker/src/query/compiler.rs delete mode 100644 kuksa_databroker/databroker/src/query/executor.rs delete mode 100644 kuksa_databroker/databroker/src/query/expr.rs delete mode 100644 kuksa_databroker/databroker/src/query/mod.rs delete mode 100644 kuksa_databroker/databroker/src/types.rs delete mode 100644 kuksa_databroker/databroker/src/viss/mod.rs delete mode 100644 kuksa_databroker/databroker/src/viss/server.rs delete mode 100644 kuksa_databroker/databroker/src/viss/v2/conversions.rs delete mode 100644 kuksa_databroker/databroker/src/viss/v2/mod.rs delete mode 100644 kuksa_databroker/databroker/src/viss/v2/server.rs delete mode 100644 kuksa_databroker/databroker/src/viss/v2/types.rs delete mode 100644 kuksa_databroker/databroker/src/vss.rs delete mode 100644 kuksa_databroker/databroker/tests/features/read_write_values.feature delete mode 100644 kuksa_databroker/databroker/tests/read_write_values.rs delete mode 100644 kuksa_databroker/databroker/tests/world/mod.rs delete mode 100644 kuksa_databroker/doc/QUERY.md delete mode 100644 kuksa_databroker/doc/TYPES.md delete mode 100644 kuksa_databroker/doc/behavior.md delete mode 100644 kuksa_databroker/doc/user_guide.md delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.py delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.pyi delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2_grpc.py delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.py delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.pyi delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2_grpc.py delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.py delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.pyi delete mode 100644 kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2_grpc.py delete mode 100644 kuksa_databroker/integration_test/helper.py delete mode 100644 kuksa_databroker/integration_test/requirements-dev.txt delete mode 100644 kuksa_databroker/integration_test/requirements.txt delete mode 100755 kuksa_databroker/integration_test/run.sh delete mode 100644 kuksa_databroker/integration_test/test_databroker.py delete mode 100755 kuksa_databroker/integration_test/update-proto.sh delete mode 100644 kuksa_databroker/lib/Cargo.lock delete mode 100644 kuksa_databroker/lib/Cargo.toml delete mode 100644 kuksa_databroker/lib/common/Cargo.toml delete mode 100644 kuksa_databroker/lib/common/src/lib.rs delete mode 100644 kuksa_databroker/lib/databroker-examples/examples/perf_setter.rs delete mode 100644 kuksa_databroker/lib/databroker-examples/examples/perf_subscriber.rs delete mode 100644 kuksa_databroker/lib/databroker-examples/src/lib.rs delete mode 100644 kuksa_databroker/lib/kuksa/Cargo.toml delete mode 100644 kuksa_databroker/lib/kuksa/src/lib.rs delete mode 100644 kuksa_databroker/lib/sdv/Cargo.toml delete mode 100644 kuksa_databroker/lib/sdv/src/lib.rs delete mode 100755 kuksa_databroker/prepare_release.sh delete mode 120000 kuksa_databroker/proto/kuksa/val/v1/README.md delete mode 120000 kuksa_databroker/proto/kuksa/val/v1/types.proto delete mode 120000 kuksa_databroker/proto/kuksa/val/v1/val.proto delete mode 100644 kuksa_databroker/proto/sdv/databroker/v1/README.md delete mode 100644 kuksa_databroker/proto/sdv/databroker/v1/broker.proto delete mode 100644 kuksa_databroker/proto/sdv/databroker/v1/collector.proto delete mode 100644 kuksa_databroker/proto/sdv/databroker/v1/types.proto delete mode 100644 proto/kuksa/val/v1/README.md delete mode 100644 proto/kuksa/val/v1/types.proto delete mode 100644 proto/kuksa/val/v1/val.proto diff --git a/.github/workflows/kuksa_databroker-cli_build.yml b/.github/workflows/kuksa_databroker-cli_build.yml deleted file mode 100644 index 07113b128..000000000 --- a/.github/workflows/kuksa_databroker-cli_build.yml +++ /dev/null @@ -1,178 +0,0 @@ -# /******************************************************************************** -# * Copyright (c) 2022,2023 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -name: kuksa_databroker-cli_build - -on: - push: - branches: [ master ] - pull_request: - paths: - - ".github/workflows/kuksa_databroker-cli_build.yml" - - "kuksa_databroker/**" - - "proto/**" - - "Cargo.*" - - "Cross.toml" - workflow_call: - workflow_dispatch: - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - lint: - name: Linting - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: cargo fmt - working-directory: ${{github.workspace}} - run: cargo fmt -- --check - - name: cargo clippy - working-directory: ${{github.workspace}} - run: cargo clippy --all-targets -- -W warnings -D warnings - check_ghcr_push: - uses: eclipse-kuksa/kuksa-actions/.github/workflows/check_ghcr_push.yml@2 - secrets: inherit - -# Run on selfhosted, because our runner has native ARM build in a remote -# builder (no need for qemu) - build-container: - runs-on: ubuntu-latest - needs: check_ghcr_push - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Building - working-directory: ${{github.workspace}}/kuksa_databroker/ - run: | - cargo install cargo-license cross - ./build-all-targets-cli.sh - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - # list of Docker images to use as base name for tags - images: | - ghcr.io/eclipse/kuksa.val/databroker-cli - # generate Docker tags based on the following events/attributes - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to the Container registry - if: needs.check_ghcr_push.outputs.push == 'true' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build kuksa.val databroker CLI container and push to ghcr.io (and ttl.sh) - id: ghcr-build - if: needs.check_ghcr_push.outputs.push == 'true' - uses: docker/build-push-action@v5 - with: - platforms: | - linux/amd64 - linux/arm64 - linux/riscv64 - file: ./kuksa_databroker/Dockerfile-cli - context: . - push: true - tags: | - ${{ steps.meta.outputs.tags }} - ttl.sh/kuksa.val/kuksa-databroker-cli-${{github.sha}} - labels: ${{ steps.meta.outputs.labels }} - # Provenance to solve that an unknown/unkown image is shown on ghcr.io - # Same problem as described in https://github.com/orgs/community/discussions/45969 - provenance: false - - - name: Build ephemeral KUKSA Databroker container and push to ttl.sh - if: needs.check_ghcr_push.outputs.push == 'false' - id: tmp-build - uses: docker/build-push-action@v5 - with: - platforms: | - linux/amd64 - linux/arm64 - linux/riscv64 - file: ./kuksa_databroker/Dockerfile-cli - context: . - push: true - tags: "ttl.sh/kuksa.val/kuksa-databroker-cli-${{github.sha}}" - labels: ${{ steps.meta.outputs.labels }} - # Provenance to solve that an unknown/unkown image is shown on ghcr.io - # Same problem as described in https://github.com/orgs/community/discussions/45969 - provenance: false - - - - name: Posting message - uses: ./.github/actions/post-container-location - with: - image: ttl.sh/kuksa.val/kuksa-databroker-cli-${{github.sha}} - - - name: "Archiving AMD64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker-cli-amd64 - path: ${{github.workspace}}/dist/amd64 - - - name: "Archiving ARM64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker-cli-arm64 - path: ${{github.workspace}}/dist/arm64 - - - name: "Archiving RISCV64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker--cli-riscv64 - path: ${{github.workspace}}/dist/riscv64 - - - bom: - name: Bill of Material Check - runs-on: ubuntu-latest - needs: build-container - - steps: - - uses: actions/checkout@v4 - - - name: "Createbom: License check and Dash output generation" - working-directory: ${{github.workspace}}/kuksa_databroker/createbom - run: | - cargo install cargo-license - python3 createbom.py --dash ${{github.workspace}}/dash-databroker-deps ../databroker - - - name: Dash license check - uses: eclipse-kuksa/kuksa-actions/check-dash@2 - with: - dashinput: ${{github.workspace}}/dash-databroker-deps diff --git a/.github/workflows/kuksa_databroker_build.yml b/.github/workflows/kuksa_databroker_build.yml deleted file mode 100644 index c24504d5c..000000000 --- a/.github/workflows/kuksa_databroker_build.yml +++ /dev/null @@ -1,248 +0,0 @@ -# /******************************************************************************** -# * Copyright (c) 2022 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -name: kuksa_databroker_build - -on: - push: - branches: [ master ] - pull_request: - paths: - - ".github/workflows/kuksa_databroker_build.yml" - - "kuksa_databroker/**" - - "proto/**" - - "Cargo.*" - - "Cross.toml" - workflow_call: - workflow_dispatch: - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - lint-and-test: - name: Linting and Testing - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - # Seems not neccessary on ubuntu-latest runner - #- uses: dtolnay/rust-toolchain@stable - - - name: "Install cargo modules" - run: cargo install cargo-tarpaulin - - - name: Show toolchain information - working-directory: ${{github.workspace}} - run: | - rustup toolchain list - cargo --version - - - name: cargo fmt - working-directory: ${{github.workspace}} - run: cargo fmt -- --check - - name: cargo clippy - working-directory: ${{github.workspace}} - run: cargo clippy --all-targets -- -W warnings -D warnings - - name: cargo clippy (feature viss) - working-directory: ${{github.workspace}} - run: cargo clippy --features viss --all-targets -- -W warnings -D warnings - - - name: Run tests and report code coverage - run: | - cargo tarpaulin -o xml \ - --exclude-files kuksa_databroker/databroker/tests/* \ - --exclude-files kuksa_databroker/databroker/tests/world/* - - - name: Upload coverage report - uses: actions/upload-artifact@v4 - with: - name: Code coverage report - path: cobertura.xml - - # - name: Publish coverage report as comment - # uses: 5monkeys/cobertura-action@v12 - # if: github.event_name == 'pull_request' - # with: - # path: cobertura.xml - # repo_token: ${{ secrets.GITHUB_TOKEN }} - # minimum_coverage: 40 - - - - check_ghcr_push: - uses: eclipse-kuksa/kuksa-actions/.github/workflows/check_ghcr_push.yml@2 - secrets: inherit - - build-container: - runs-on: ubuntu-latest - - needs: check_ghcr_push - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Building - working-directory: ${{github.workspace}}/kuksa_databroker/ - run: | - cargo install cargo-license cross - ./build-all-targets.sh - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - # list of Docker images to use as base name for tags - images: | - ghcr.io/eclipse/kuksa.val/databroker - # generate Docker tags based on the following events/attributes - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - # only needed for runners without buildx setup, will be slow - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to the Container registry - if: needs.check_ghcr_push.outputs.push == 'true' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build kuksa.val databroker container container and push to ghcr.io (and ttl.sh) - id: ghcr-build - if: needs.check_ghcr_push.outputs.push == 'true' - uses: docker/build-push-action@v5 - with: - platforms: | - linux/amd64 - linux/arm64 - linux/riscv64 - file: ./kuksa_databroker/Dockerfile - context: . - push: true - tags: | - ${{ steps.meta.outputs.tags }} - ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}} - labels: ${{ steps.meta.outputs.labels }} - # Provenance to solve that an unknown/unkown image is shown on ghcr.io - # Same problem as described in https://github.com/orgs/community/discussions/45969 - provenance: false - - - name: Build ephemeral KUKSA Databroker container and push to ttl.sh - if: needs.check_ghcr_push.outputs.push == 'false' - id: tmp-build - uses: docker/build-push-action@v5 - with: - platforms: | - linux/amd64 - linux/arm64 - linux/riscv64 - file: ./kuksa_databroker/Dockerfile - context: . - push: true - tags: "ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}}" - labels: ${{ steps.meta.outputs.labels }} - # Provenance to solve that an unknown/unkown image is shown on ghcr.io - # Same problem as described in https://github.com/orgs/community/discussions/45969 - provenance: false - - - name: Posting message - uses: ./.github/actions/post-container-location - with: - image: ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}} - - - name: "Archiving AMD64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker-amd64 - path: ${{github.workspace}}/dist/amd64 - - - name: "Archiving ARM64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker-arm64 - path: ${{github.workspace}}/dist/arm64 - - - name: "Archiving RISCV64 artifacts" - uses: actions/upload-artifact@v4 - with: - name: databroker-riscv64 - path: ${{github.workspace}}/dist/riscv64 - - - integration-test: - name: Run integration test - runs-on: ubuntu-latest - needs: [build-container] - - steps: - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - uses: actions/checkout@v4 - - - name: Run integration test on AMD64 container - env: - DATABROKER_IMAGE: ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}} - CONTAINER_PLATFORM: linux/amd64 - run: | - ${{github.workspace}}/kuksa_databroker/integration_test/run.sh - - - name: Run integration test on ARM64 container - env: - DATABROKER_IMAGE: ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}} - CONTAINER_PLATFORM: linux/arm64 - run: | - ${{github.workspace}}/kuksa_databroker/integration_test/run.sh - - - name: Run integration test on RISCV64 container - env: - DATABROKER_IMAGE: ttl.sh/kuksa.val/kuksa-databroker-${{github.sha}} - CONTAINER_PLATFORM: linux/riscv64 - run: | - ${{github.workspace}}/kuksa_databroker/integration_test/run.sh - - bom: - name: Bill of Material Check - runs-on: ubuntu-latest - needs: build-container - - steps: - - uses: actions/checkout@v4 - - - name: "Createbom: License check and Dash output generation" - working-directory: ${{github.workspace}}/kuksa_databroker/createbom - run: | - cargo install cargo-license - python3 createbom.py --dash ${{github.workspace}}/dash-databroker-deps ../databroker - - - name: Dash license check - uses: eclipse-kuksa/kuksa-actions/check-dash@2 - with: - dashinput: ${{github.workspace}}/dash-databroker-deps diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 2be5dbce9..000000000 --- a/Cargo.lock +++ /dev/null @@ -1,3622 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstream" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" - -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "async-trait" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "autotools" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" -dependencies = [ - "cc", -] - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "base64 0.21.7", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1", - "sync_wrapper", - "tokio", - "tokio-tungstenite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" -dependencies = [ - "memchr", - "regex-automata 0.4.6", - "serde", -] - -[[package]] -name = "btoi" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad" -dependencies = [ - "num-traits", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytecount" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.5", -] - -[[package]] -name = "clap" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "clru" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "console" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.52.0", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cucumber" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5063d8cf24f4998ad01cac265da468a15ca682a8f4f826d50e661964e8d9b8" -dependencies = [ - "anyhow", - "async-trait", - "clap", - "console", - "cucumber-codegen", - "cucumber-expressions", - "derive_more", - "drain_filter_polyfill", - "either", - "futures", - "gherkin", - "globwalk", - "humantime", - "inventory", - "itertools 0.12.1", - "lazy-regex", - "linked-hash-map", - "once_cell", - "pin-project", - "regex", - "sealed", - "serde", - "serde_json", - "smart-default", -] - -[[package]] -name = "cucumber-codegen" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01091e28d1f566c8b31b67948399d2efd6c0a8f6228a9785519ed7b73f7f0aef" -dependencies = [ - "cucumber-expressions", - "inflections", - "itertools 0.12.1", - "proc-macro2", - "quote", - "regex", - "syn 2.0.60", - "synthez", -] - -[[package]] -name = "cucumber-expressions" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d794fed319eea24246fb5f57632f7ae38d61195817b7eb659455aa5bdd7c1810" -dependencies = [ - "derive_more", - "either", - "nom", - "nom_locate", - "regex", - "regex-syntax 0.7.5", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "databroker" -version = "0.4.3" -dependencies = [ - "anyhow", - "axum", - "chrono", - "clap", - "cucumber", - "databroker-proto", - "futures", - "jemallocator", - "jsonwebtoken", - "kuksa", - "kuksa-common", - "lazy_static", - "prost", - "prost-types", - "regex", - "sd-notify", - "serde", - "serde_json", - "sqlparser", - "thiserror", - "tokio", - "tokio-stream", - "tonic", - "tracing", - "tracing-subscriber", - "uuid", - "vergen", -] - -[[package]] -name = "databroker-cli" -version = "0.4.3" -dependencies = [ - "ansi_term", - "clap", - "databroker-proto", - "http", - "kuksa", - "kuksa-common", - "kuksa-sdv", - "linefeed", - "prost", - "prost-types", - "regex", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "databroker-proto" -version = "0.4.3" -dependencies = [ - "prost", - "prost-types", - "protobuf-src", - "tonic", - "tonic-build", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users 0.4.5", - "winapi", -] - -[[package]] -name = "drain_filter_polyfill" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" - -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "either" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "faster-hex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "gherkin" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b79820c0df536d1f3a089a2fa958f61cb96ce9e0f3f8f507f5a31179567755" -dependencies = [ - "heck 0.4.1", - "peg", - "quote", - "serde", - "serde_json", - "syn 2.0.60", - "textwrap", - "thiserror", - "typed-builder", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "gix" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd025382892c7b500a9ce1582cd803f9c2ebfe44aff52e9c7f86feee7ced75e" -dependencies = [ - "gix-actor", - "gix-commitgraph", - "gix-config", - "gix-date", - "gix-diff", - "gix-discover", - "gix-features", - "gix-fs", - "gix-glob", - "gix-hash", - "gix-hashtable", - "gix-index", - "gix-lock", - "gix-macros", - "gix-object", - "gix-odb", - "gix-pack", - "gix-path", - "gix-ref", - "gix-refspec", - "gix-revision", - "gix-revwalk", - "gix-sec", - "gix-tempfile", - "gix-trace", - "gix-traverse", - "gix-url", - "gix-utils", - "gix-validate", - "once_cell", - "parking_lot", - "signal-hook", - "smallvec", - "thiserror", - "unicode-normalization", -] - -[[package]] -name = "gix-actor" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da27b5ab4ab5c75ff891dccd48409f8cc53c28a79480f1efdd33184b2dc1d958" -dependencies = [ - "bstr", - "btoi", - "gix-date", - "itoa", - "thiserror", - "winnow", -] - -[[package]] -name = "gix-bitmap" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae" -dependencies = [ - "thiserror", -] - -[[package]] -name = "gix-chunk" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c8751169961ba7640b513c3b24af61aa962c967aaf04116734975cd5af0c52" -dependencies = [ - "thiserror", -] - -[[package]] -name = "gix-commitgraph" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8dcbf434951fa477063e05fea59722615af70dc2567377e58c2f7853b010fc" -dependencies = [ - "bstr", - "gix-chunk", - "gix-features", - "gix-hash", - "memmap2", - "thiserror", -] - -[[package]] -name = "gix-config" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367304855b369cadcac4ee5fb5a3a20da9378dd7905106141070b79f85241079" -dependencies = [ - "bstr", - "gix-config-value", - "gix-features", - "gix-glob", - "gix-path", - "gix-ref", - "gix-sec", - "memchr", - "once_cell", - "smallvec", - "thiserror", - "unicode-bom", - "winnow", -] - -[[package]] -name = "gix-config-value" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804" -dependencies = [ - "bitflags 2.5.0", - "bstr", - "gix-path", - "libc", - "thiserror", -] - -[[package]] -name = "gix-date" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180b130a4a41870edfbd36ce4169c7090bca70e195da783dea088dd973daa59c" -dependencies = [ - "bstr", - "itoa", - "thiserror", - "time", -] - -[[package]] -name = "gix-diff" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6a0454f8c42d686f17e7f084057c717c082b7dbb8209729e4e8f26749eb93a" -dependencies = [ - "bstr", - "gix-hash", - "gix-object", - "thiserror", -] - -[[package]] -name = "gix-discover" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d7b2896edc3d899d28a646ccc6df729827a6600e546570b2783466404a42d6" -dependencies = [ - "bstr", - "dunce", - "gix-hash", - "gix-path", - "gix-ref", - "gix-sec", - "thiserror", -] - -[[package]] -name = "gix-features" -version = "0.37.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50270e8dcc665f30ba0735b17984b9535bdf1e646c76e638e007846164d57af" -dependencies = [ - "crc32fast", - "flate2", - "gix-hash", - "gix-trace", - "libc", - "once_cell", - "prodash", - "sha1_smol", - "thiserror", - "walkdir", -] - -[[package]] -name = "gix-fs" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7555c23a005537434bbfcb8939694e18cad42602961d0de617f8477cc2adecdd" -dependencies = [ - "gix-features", -] - -[[package]] -name = "gix-glob" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6232f18b262770e343dcdd461c0011c9b9ae27f0c805e115012aa2b902c1b8" -dependencies = [ - "bitflags 2.5.0", - "bstr", - "gix-features", - "gix-path", -] - -[[package]] -name = "gix-hash" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e" -dependencies = [ - "faster-hex", - "thiserror", -] - -[[package]] -name = "gix-hashtable" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddf80e16f3c19ac06ce415a38b8591993d3f73aede049cb561becb5b3a8e242" -dependencies = [ - "gix-hash", - "hashbrown 0.14.5", - "parking_lot", -] - -[[package]] -name = "gix-index" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e50e63df6c8d4137f7fb882f27643b3a9756c468a1a2cdbe1ce443010ca8778" -dependencies = [ - "bitflags 2.5.0", - "bstr", - "btoi", - "filetime", - "gix-bitmap", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-traverse", - "itoa", - "libc", - "memmap2", - "rustix", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-lock" -version = "12.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40a439397f1e230b54cf85d52af87e5ea44cc1e7748379785d3f6d03d802b00" -dependencies = [ - "gix-tempfile", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-macros" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dff438f14e67e7713ab9332f5fd18c8f20eb7eb249494f6c2bf170522224032" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "gix-object" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c89402e8faa41b49fde348665a8f38589e461036475af43b6b70615a6a313a2" -dependencies = [ - "bstr", - "btoi", - "gix-actor", - "gix-date", - "gix-features", - "gix-hash", - "gix-validate", - "itoa", - "smallvec", - "thiserror", - "winnow", -] - -[[package]] -name = "gix-odb" -version = "0.56.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46ae6da873de41c6c2b73570e82c571b69df5154dcd8f46dfafc6687767c33b1" -dependencies = [ - "arc-swap", - "gix-date", - "gix-features", - "gix-hash", - "gix-object", - "gix-pack", - "gix-path", - "gix-quote", - "parking_lot", - "tempfile", - "thiserror", -] - -[[package]] -name = "gix-pack" -version = "0.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782b4d42790a14072d5c400deda9851f5765f50fe72bca6dece0da1cd6f05a9a" -dependencies = [ - "clru", - "gix-chunk", - "gix-features", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-path", - "gix-tempfile", - "memmap2", - "parking_lot", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-path" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23623cf0f475691a6d943f898c4d0b89f5c1a2a64d0f92bce0e0322ee6528783" -dependencies = [ - "bstr", - "gix-trace", - "home", - "once_cell", - "thiserror", -] - -[[package]] -name = "gix-quote" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbff4f9b9ea3fa7a25a70ee62f545143abef624ac6aa5884344e70c8b0a1d9ff" -dependencies = [ - "bstr", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-ref" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d9bd1984638d8f3511a2fcbe84fcedb8a5b5d64df677353620572383f42649" -dependencies = [ - "gix-actor", - "gix-date", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-path", - "gix-tempfile", - "gix-validate", - "memmap2", - "thiserror", - "winnow", -] - -[[package]] -name = "gix-refspec" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be219df5092c1735abb2a53eccdf775e945eea6986ee1b6e7a5896dccc0be704" -dependencies = [ - "bstr", - "gix-hash", - "gix-revision", - "gix-validate", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-revision" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa78e1df3633bc937d4db15f8dca2abdb1300ca971c0fabcf9fa97e38cf4cd9f" -dependencies = [ - "bstr", - "gix-date", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-revwalk", - "gix-trace", - "thiserror", -] - -[[package]] -name = "gix-revwalk" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702de5fe5c2bbdde80219f3a8b9723eb927466e7ecd187cfd1b45d986408e45f" -dependencies = [ - "gix-commitgraph", - "gix-date", - "gix-hash", - "gix-hashtable", - "gix-object", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-sec" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1" -dependencies = [ - "bitflags 2.5.0", - "gix-path", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "gix-tempfile" -version = "12.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8ef376d718b1f5f119b458e21b00fbf576bc9d4e26f8f383d29f5ffe3ba3eaa" -dependencies = [ - "gix-fs", - "libc", - "once_cell", - "parking_lot", - "signal-hook", - "signal-hook-registry", - "tempfile", -] - -[[package]] -name = "gix-trace" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e" - -[[package]] -name = "gix-traverse" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65109e445ba7a409b48f34f570a4d7db72eade1dc1bcff81990a490e86c07161" -dependencies = [ - "gix-commitgraph", - "gix-date", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-revwalk", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-url" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0f17cceb7552a231d1fec690bc2740c346554e3be6f5d2c41dfa809594dc44" -dependencies = [ - "bstr", - "gix-features", - "gix-path", - "home", - "thiserror", - "url", -] - -[[package]] -name = "gix-utils" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc" -dependencies = [ - "fastrand", - "unicode-normalization", -] - -[[package]] -name = "gix-validate" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39fc6e06044985eac19dd34d474909e517307582e462b2eb4c8fa51b6241545" -dependencies = [ - "bstr", - "thiserror", -] - -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.6", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "inflections" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" - -[[package]] -name = "inventory" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jemalloc-sys" -version = "0.5.4+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "jemallocator" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc" -dependencies = [ - "jemalloc-sys", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "9.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" -dependencies = [ - "base64 0.21.7", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "kuksa" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "kuksa-common", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "kuksa-common" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "kuksa-sdv" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "kuksa-common", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "lazy-regex" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" -dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", -] - -[[package]] -name = "lazy-regex-proc_macros" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.60", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.5.0", - "libc", -] - -[[package]] -name = "linefeed" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28715d08e35c6c074f9ae6b2e6a2420bac75d050c66ecd669d7d5b98e2caa036" -dependencies = [ - "dirs 1.0.5", - "mortal", - "winapi", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "memmap2" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" -dependencies = [ - "libc", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "mortal" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c624fa1b7aab6bd2aff6e9b18565cc0363b6d45cbcd7465c9ed5e3740ebf097" -dependencies = [ - "bitflags 2.5.0", - "libc", - "nix", - "smallstr", - "terminfo", - "unicode-normalization", - "unicode-width", - "winapi", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nom_locate" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3" -dependencies = [ - "bytecount", - "memchr", - "nom", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.1", - "smallvec", - "windows-targets 0.52.5", -] - -[[package]] -name = "peg" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367" -dependencies = [ - "peg-macros", - "peg-runtime", -] - -[[package]] -name = "peg-macros" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" -dependencies = [ - "peg-runtime", - "proc-macro2", - "quote", -] - -[[package]] -name = "peg-runtime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" - -[[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64 0.22.0", - "serde", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro2" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prodash" -version = "28.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "protobuf-src" -version = "1.1.0+21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" -dependencies = [ - "autotools", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.14", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - -[[package]] -name = "redox_users" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" -dependencies = [ - "getrandom 0.2.14", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.3", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.14", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64 0.13.1", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sd-notify" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32" - -[[package]] -name = "sealed" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.199" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.199" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "serde_json" -version = "1.0.116" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallstr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e922794d168678729ffc7e07182721a14219c65814e66e91b839a272fe5ae4f" -dependencies = [ - "smallvec", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "smart-default" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "socket2" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "sqlparser" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9a527b68048eb95495a1508f6c8395c8defcff5ecdbe8ad4106d08a2ef2a3c" -dependencies = [ - "log", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synthez" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d2c2202510a1e186e63e596d9318c91a8cbe85cd1a56a7be0c333e5f59ec8d" -dependencies = [ - "syn 2.0.60", - "synthez-codegen", - "synthez-core", -] - -[[package]] -name = "synthez-codegen" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f724aa6d44b7162f3158a57bccd871a77b39a4aef737e01bcdff41f4772c7746" -dependencies = [ - "syn 2.0.60", - "synthez-core", -] - -[[package]] -name = "synthez-core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bfa6ec52465e2425fd43ce5bbbe0f0b623964f7c63feb6b10980e816c654ea" -dependencies = [ - "proc-macro2", - "quote", - "sealed", - "syn 2.0.60", -] - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "terminal_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "terminfo" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666cd3a6681775d22b200409aad3b089c5b99fb11ecdd8a204d9d62f8148498f" -dependencies = [ - "dirs 4.0.0", - "fnv", - "nom", - "phf", - "phf_codegen", -] - -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.21.7", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typed-builder" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe83c85a85875e8c4cb9ce4a890f05b23d38cd0d47647db7895d3d2a79566d2" -dependencies = [ - "typed-builder-macro", -] - -[[package]] -name = "typed-builder-macro" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a3151c41d0b13e3d011f98adc24434560ef06673a155a6c7f66b9879eecce2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-bom" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom 0.2.14", -] - -[[package]] -name = "vergen" -version = "8.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525" -dependencies = [ - "anyhow", - "cargo_metadata", - "cfg-if", - "gix", - "regex", - "rustversion", - "time", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.60", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 7e33fe957..000000000 --- a/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[workspace] - -resolver = "2" - -members = [ - "kuksa_databroker/databroker", - "kuksa_databroker/databroker-proto", - "kuksa_databroker/databroker-cli", -] - -exclude = [ - "kuksa_databroker/lib/*" -] - -[workspace.dependencies] -clap = { version = "4.2", default-features = false } -databroker-proto = { path = "kuksa_databroker/databroker-proto" } -# prost has no features -prost = "0.11" -# prost-types has no features -prost-types = "0.11" -# tokio does not enable features by default -tokio = "1.17.0" -# tokio-stream has no features -tokio-stream = "0.1.8" -tonic = { version = "0.9.1", default-features = false } -tonic-build = { version = "0.8", default-features = false } - -[profile.release] -lto = true # Link time optimization (dead code removal etc...) -opt-level = "s" -codegen-units = 1 -incremental = false -strip = true -# debug = true # for profiling (turn off otherwise) -# split-debuginfo = "packed" # only enable when `debug = true`` diff --git a/Cross.toml b/Cross.toml deleted file mode 100644 index 734a08bcc..000000000 --- a/Cross.toml +++ /dev/null @@ -1,15 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[build.env] -passthrough = ["RUSTFLAGS"] diff --git a/README.md b/README.md index c802ac80a..1fbd93374 100644 --- a/README.md +++ b/README.md @@ -23,17 +23,16 @@ If you are new here, try the [Quickstart](doc/quickstart.md), which should not t [![Gitter](https://img.shields.io/gitter/room/kuksa-val/community)](https://gitter.im/kuksa-val/community) [![Build kuksa-val-server](https://github.com/eclipse/kuksa.val/actions/workflows/kuksa_val_docker.yml/badge.svg)](https://github.com/eclipse/kuksa.val/actions/workflows/kuksa_val_docker.yml?query=branch%3Amaster) -[![Build kuksa-databroker](https://github.com/eclipse/kuksa.val/actions/workflows/kuksa_databroker_build.yml/badge.svg)](https://github.com/eclipse/kuksa.val/actions/workflows/kuksa_databroker_build.yml?query=branch%3Amaster) [![codecov](https://codecov.io/gh/eclipse/kuksa.val/branch/master/graph/badge.svg?token=M4FT175771)](https://codecov.io/gh/eclipse/kuksa.val) KUKSA.val contains several components | Component | Description | | -------------- | ----------- | -| [KUKSA Databroker](https://github.com/eclipse-kuksa/kuksa-databroker) | Efficient in-vehicle signal broker written in RUST providing authorized access to VSS data using gRPC *Note: Moved to a separate repository!* +| [KUKSA Databroker](https://github.com/eclipse-kuksa/kuksa-databroker) | Efficient in-vehicle signal broker written in RUST providing authorized access to VSS data using gRPC *Note: Moved to the [kuksa-databroker](https://github.com/eclipse-kuksa/kuksa-databroker) repository! Last commit with Databroker from this repository available in the [deprecated_databroker](https://github.com/eclipse/kuksa.val/tree/deprecated_databroker) branch!* | [KUKSA Server](kuksa-val-server) | Feature rich in-vehicle data server written in C++ providing authorized access to VSS data using W3C VISS websocket protocol **Note: KUKSA Server is deprecated and will reach End-of-Life 2024-12-31!** -| [KUKSA Python SDK](https://github.com/eclipse-kuksa/kuksa-python-sdk) | Command line tool to interactively explore and modify the VSS data points and data structure. Python library for easy interaction with KUKSA Databroker and Server. *Note: Moved to a separate repository!* -| [KUKSA GO Client](https://github.com/eclipse-kuksa/kuksa-incubation/tree/main/kuksa_go_client) | Example client written in the [GO](https://go.dev/) programming language for easy interaction with KUKSA Databroker and Server *Note: Moved to a separate repository!* +| [KUKSA Python SDK](https://github.com/eclipse-kuksa/kuksa-python-sdk) | Command line tool to interactively explore and modify the VSS data points and data structure. Python library for easy interaction with KUKSA Databroker and Server. *Note: Moved to [kuksa-python-sdk](https://github.com/eclipse-kuksa/kuksa-python-sdk) repository!* +| [KUKSA GO Client](https://github.com/eclipse-kuksa/kuksa-incubation/tree/main/kuksa_go_client) | Example client written in the [GO](https://go.dev/) programming language for easy interaction with KUKSA Databroker and Server *Note: Moved to a [kuksa-incubation](https://github.com/eclipse-kuksa/kuksa-incubation/tree/main/kuksa_go_client) repository!* | [Example Applications](./kuksa_apps) | Some example apps for different programming languages and frameworks | [Feeders and Providers](https://github.com/eclipse/kuksa.val.feeders/) | Multiple feeders and providers for exchanging vehicle data with KUKSA databroker and Server diff --git a/jwt/README.md b/jwt/README.md deleted file mode 100644 index 1663983c2..000000000 --- a/jwt/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Databroker Example Tokens - -*NOTE: The tokens here are copies of the tokens stored in [kuksa-common](https://github.com/eclipse-kuksa/kuksa-common/tree/main/jwt)!* - - -This directory contains example tokens for demo and test purposes for KUKSA.val Databroker. -For more information on token format see [documentation](../doc/KUKSA.val_data_broker/authorization.md). - -## Available tokens - - -* `actuate-provide-all.token` - gives access to set target value and actual value for all signals -* `provide-all.token` - gives access to set actual value for all signals, but not target value -* `read-all.token` - gives access to read actual and current value for all signals -* `provide-vehicle-speed.token` - gives access to write and read actual value for Vehicle.Speed. Does not give access to other signals -* `read-vehicle-speed.token` - gives access to read actual value for Vehicle.Speed. Does not give access to other signals - - -## Create new tokens - -Helper scripts and documentation on how to generate new keys and tokens exist in -[kuksa-common](https://github.com/eclipse-kuksa/kuksa-common/tree/main/jwt). diff --git a/jwt/actuate-provide-all.json b/jwt/actuate-provide-all.json deleted file mode 100644 index c049a9353..000000000 --- a/jwt/actuate-provide-all.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sub": "local dev", - "iss": "createToken.py", - "aud": [ - "kuksa.val" - ], - "iat": 1516239022, - "exp": 1767225599, - "scope": "actuate provide" -} \ No newline at end of file diff --git a/jwt/actuate-provide-all.token b/jwt/actuate-provide-all.token deleted file mode 100644 index 110d3c413..000000000 --- a/jwt/actuate-provide-all.token +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoiYWN0dWF0ZSBwcm92aWRlIn0.x-bUZwDCC663wGYrWCYjQZwQWhN1CMuKgxuIN5dUF_izwMutiqF6Xc-tnXgZa93BbT3I74WOMk4awKHBUSTWekGs3-qF6gajorbat6n5180TOqvNu4CXuIPZN5zpngf4id3smMkKOT699tPnSEbmlkj4vk-mIjeOAU-FcYA-VbkKBTsjvfFgKa2OdB5h9uZARBg5Rx7uBN3JsH1I6j9zoLid184Ewa6bhU2qniFt5iPsGJniNsKsRrrndN1KzthO13My44s56yvwSHIOrgDGbXdja_eLuOVOq9pHCjCtorPScgEuUUE4aldIuML-_j397taNP9Y3VZYVvofEK7AuiePTbzwxrZ1RAjK74h1-4ued3A2gUTjr5BsRlc9b7eLZzxLJkrqdfGAzBh_rtrB7p32TbvpjeFP30NW6bB9JS43XACUUm_S_RcyI7BLuUdnFyQDQr6l6sRz9XayYXceilHdCxbAVN0HVnBeui5Bb0mUZYIRZeY8k6zcssmokANTD8ZviDMpKlOU3t5AlXJ0nLkgyMhV9IUTwPUv6F8BTPc-CquJCUNbTyo4ywTSoODWbm3PmQ3Y46gWF06xqnB4wehLscBdVk3iAihQp3tckGhMnx5PI_Oy7utIncr4pRCMos63TnBkfrl7d43cHQTuK0kO76EWtv4ODEHgLvEAv4HA \ No newline at end of file diff --git a/jwt/provide-all.json b/jwt/provide-all.json deleted file mode 100644 index b71c3536f..000000000 --- a/jwt/provide-all.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sub": "local dev", - "iss": "createToken.py", - "aud": [ - "kuksa.val" - ], - "iat": 1516239022, - "exp": 1767225599, - "scope": "provide" -} \ No newline at end of file diff --git a/jwt/provide-all.token b/jwt/provide-all.token deleted file mode 100644 index 8ce854f34..000000000 --- a/jwt/provide-all.token +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicHJvdmlkZSJ9.OJWzTvDjcmeWyg3vmBR5TEtqYaHq8HrpFLlTKZAfDBAQBUHpyUEboJ97jfWuWgBnTpnfboyfAbwvLqo6bEVZ6tXzF8n9LtW6HmPbIWoDqXuobM2grUCVaGKuOcnCpMCQYChziqHbYwRJYP9nkYgbQU1kE4dN7880Io4xzq0GEbWksB2CVpOoExQUmCZpCohPs-XEkdmXhcUKnWnOeiSsRGKusx987vpY_WOXh6WE7DfJgzAgpPDo33qI7zQuTzUILORQsiHmsrQO0-zcvokNjaQUzlt5ETZ7MQLCtiUQaN0NMbDMCWkmSfNvZ5hKCNbfr2FaiMzrGBOQdvQiFo-DqZKGNweaGpufYXuaKfn3SXKoDr8u1xDE5oKgWMjxDR9pQYGzIF5bDXITSywCm4kN5DIn7e2_Ga28h3rBl0t0ZT0cwlszftQRueDTFcMns1u9PEDOqf7fRrhjq3zqpxuMAoRANVd2z237eBsS0AvdSIxL52N4xO8P_h93NN8Vaum28fTPxzm8p9WlQh4mgUelggtT415hLcxizx15ARIRG0RiW91Pglzt4WRtXHnsg93Ixd3yXXzZ2i4Y0hqhj_L12SsXunK2VxKup2sFCQz6wM-t_7ADmNYcs80idzsadY8rYKDV8N1WqOOd4ANG_nzWa86Tyu6wAwhDVag5nbFmLZQ \ No newline at end of file diff --git a/jwt/provide-vehicle-speed.json b/jwt/provide-vehicle-speed.json deleted file mode 100644 index c5780b337..000000000 --- a/jwt/provide-vehicle-speed.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sub": "local dev", - "iss": "createToken.py", - "aud": [ - "kuksa.val" - ], - "iat": 1516239022, - "exp": 1767225599, - "scope": "provide:Vehicle.Speed" -} \ No newline at end of file diff --git a/jwt/provide-vehicle-speed.token b/jwt/provide-vehicle-speed.token deleted file mode 100644 index 8f33ac2c8..000000000 --- a/jwt/provide-vehicle-speed.token +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicHJvdmlkZTpWZWhpY2xlLlNwZWVkIn0.WlHkTSverOeprozFHG5Oo14c_Qr0NL9jv3ObAK4S10ddbqFRjWttkY9C0ehLqM6vXNUyI9uimbrM5FSPpw058mWGbOaEc8l1ImjS-DBKkDXyFkSlMoCPuWfhbamfFWTfY-K_K21kTs0hvr-FGRREC1znnZx0TFEi9HQO2YJvsSfJ7-6yo1Wfplvhf3NCa-sC5PrZEEbvYLkTB56C--0waqxkLZGx_SAo_XoRCijJ3s_LnrEbp61kT9CVYmNk017--mA9EEcjpHceOOtj1_UVjHpLKHOxitjpF-7LQNdq2kCY-Y2qv9vf8H6nAFVG8QKAUAaFb0CmYpDIdK8XSLRD7yLd6JnoRswBqmveFCUpmdrMYsSgut1JH4oCn5EnJ-c5UfZ4IRDgc7iBE5cqH9ao7j5PItsE9tYQJDAfygel3sYnIzuAd-DMYyPs1Jj9BzrAWEmI9s0PelA0KAEspmNufn9e-mjeC050e5NhhzJ4Vj_ffbOBzgx1vgLAaoMj5dOb4j3OpNC0XoUgGfR-YbTLi48h6uXEnxsXNGblOlSqTBmy2iZhYpfLBIsdvQTzKf2iYkw_TLo5LE5p9m4aUKFywcyGPMxzVcA8JIJ2g2Xp30RnIAxUlDTXcuYDGYRgKiGJb0rq1yQVl3RCnKaxTVHg8qqHkts_B-cbItlZP8bJA5M \ No newline at end of file diff --git a/jwt/read-all.json b/jwt/read-all.json deleted file mode 100644 index fe04b0379..000000000 --- a/jwt/read-all.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sub": "local dev", - "iss": "createToken.py", - "aud": [ - "kuksa.val" - ], - "iat": 1516239022, - "exp": 1767225599, - "scope": "read" -} \ No newline at end of file diff --git a/jwt/read-all.token b/jwt/read-all.token deleted file mode 100644 index 10fafb537..000000000 --- a/jwt/read-all.token +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicmVhZCJ9.P6tJPRSJWB51UOFDFs8qQ-lGqb1NoWgCekHUKyMiYcs8sR3FGVKSRjSkcqv1tXOlILvqhUwyuTKui25_kFKkTPv47GI0xAqcXtaTmDwHAWZHFC6HWGWGXohu7XvURrim5kMRVHy_VGlzasGgVap0JFk3wmaY-nyFYL_PLDjvGjIQuOwFiUtKK1PfiKviZKyc5EzPUEAoHxFL_BSOsTdDDcaydFe9rSKJzpYrj7qXY0hMJCje2BUGlSUIttR95aSjOZflSxiGystWHME8fKMmDERAx749Jpt37M3taCxBsUzER5olPz65MGzFSikfC-jH_KGmJ4zNYS65_OM1a-CPfW7Ts__pyAXxFULNMHRMIfh8Wiig4UcooMy_ZJO_DN2rq95XdaBbzRua5mxvO2wM6iu5kv4lhNxhjVNGuWFRLLJ_icBUZlvAuC3eqp66B-Y3jJNI0cSnIvsVX8YFVS3ebW8tf40OdeVou8fWZPcQsFAAafBhIxNOW8FbLZ9sRvQ-FGwZy-GyF52IJ5ZKeGfAkeEh9ZLIcyJ2YlGp4q0EOKIdwIBsWfCFtZbAvi2ornO3XvJm94NBqprpvQYN_IB7yyRxDduLjNKqqcFqnrlWYI-ZhvghWH2rEblplgHZdyVD1G9Mbv0_zdNTKFs6J7IP96aV6-4hBOt3kROlS1G7ObA \ No newline at end of file diff --git a/jwt/read-vehicle-speed.json b/jwt/read-vehicle-speed.json deleted file mode 100644 index 0c08f5151..000000000 --- a/jwt/read-vehicle-speed.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sub": "local dev", - "iss": "createToken.py", - "aud": [ - "kuksa.val" - ], - "iat": 1516239022, - "exp": 1767225599, - "scope": "read:Vehicle.Speed" -} \ No newline at end of file diff --git a/jwt/read-vehicle-speed.token b/jwt/read-vehicle-speed.token deleted file mode 100644 index 82a9550ea..000000000 --- a/jwt/read-vehicle-speed.token +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicmVhZDpWZWhpY2xlLlNwZWVkIn0.QyaKO-vjjzeimAAyUMjlM_jAvhlmYVguzXp76jAnW9UUiWowrXeYTa_ERVzZqxz21txq1QQmee8WtCO978w95irSRugTmlydWNjS6xPGAOCan6TEXBryrmR5FSmm6fPNrgLPhFEfcqFIQm07B286JTU98s-s2yeb6bJRpm7gOzhH5klCLxBPFYNncwdqqaT6aQD31xOcq4evooPOoV5KZFKI9WKkzOclDvto6TCLYIgnxu9Oey_IqyRAkDHybeFB7LR-1XexweRjWKleXGijpNweu6ATsbPakeVIfJ6k3IN-oKNvP6nawtBg7GeSEFYNksUUCVrIg8b0_tZi3c3E114MvdiDe7iWfRd5SDjO1f8nKiqDYy9P-hwejHntsaXLZbWSs_GNbWmi6J6pwgdM4XI3x4vx-0Otsb4zZ0tOmXjIL_tRsKA5dIlSBYEpIZq6jSXgQLN2_Ame0i--gGt4jTg1sYJHqE56BKc74HqkcvrQAZrZcoeqiKkwKcy6ofRpIQ57ghooZLkJ8BLWEV_zJgSffHBX140EEnMg1z8GAhrsbGvJ29TmXGmYyLrAhyTj_L6aNCZ1XEkbK0Yy5pco9sFGRm9nKTeFcNICogPuzbHg4xsGX_SZgUmla8Acw21AAXwuFY60_aFDUlCKZh93Z2SAruz1gfNIL43I0L8-wfw \ No newline at end of file diff --git a/kuksa_databroker/.dockerignore b/kuksa_databroker/.dockerignore deleted file mode 100644 index f4ceea785..000000000 --- a/kuksa_databroker/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -**/target/ diff --git a/kuksa_databroker/.gitignore b/kuksa_databroker/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/kuksa_databroker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/kuksa_databroker/DEPENDENCIES b/kuksa_databroker/DEPENDENCIES deleted file mode 100644 index 06df9e6f2..000000000 --- a/kuksa_databroker/DEPENDENCIES +++ /dev/null @@ -1,134 +0,0 @@ -crate/cratesio/-/aho-corasick/0.7.20, MIT AND Unlicense, approved, #4240 -crate/cratesio/-/ansi_term/0.12.1, MIT, approved, clearlydefined -crate/cratesio/-/anyhow/1.0.68, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/arrayref/0.3.6, BSD-2-Clause, approved, clearlydefined -crate/cratesio/-/arrayvec/0.5.2, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/async-stream-impl/0.3.3, MIT, approved, clearlydefined -crate/cratesio/-/async-stream/0.3.3, MIT, approved, clearlydefined -crate/cratesio/-/async-trait/0.1.63, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #6666 -crate/cratesio/-/base64/0.13.1, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #6655 -crate/cratesio/-/bitflags/1.3.2, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/blake2b_simd/0.5.11, MIT, approved, clearlydefined -crate/cratesio/-/bytes/1.3.0, MIT, approved, clearlydefined -crate/cratesio/-/cfg-if/1.0.0, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/clap/3.2.23, Apache-2.0 AND MIT, approved, #4243 -crate/cratesio/-/clap_lex/0.2.4, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #4254 -crate/cratesio/-/constant_time_eq/0.1.5, CC0-1.0, approved, clearlydefined -crate/cratesio/-/crossbeam-utils/0.8.14, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/dirs-sys/0.3.7, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/dirs/1.0.5, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/dirs/4.0.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/either/1.8.0, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #4245 -crate/cratesio/-/fnv/1.0.7, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/futures-channel/0.3.25, Apache-2.0 AND MIT AND Apache-2.0 AND MIT AND BSD-2-Clause-Views, approved, #6671 -crate/cratesio/-/futures-core/0.3.25, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/futures-sink/0.3.25, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/futures-task/0.3.25, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/futures-util/0.3.25, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/getrandom/0.1.16, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/getrandom/0.2.8, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/h2/0.3.15, MIT, approved, clearlydefined -crate/cratesio/-/hashbrown/0.12.3, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/hermit-abi/0.2.6, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/http-body/0.4.5, MIT, approved, clearlydefined -crate/cratesio/-/http/0.2.8, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/httparse/1.8.0, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #4256 -crate/cratesio/-/httpdate/1.0.2, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/hyper-timeout/0.4.1, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/hyper/0.14.23, MIT, approved, clearlydefined -crate/cratesio/-/indexmap/1.9.2, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/itertools/0.10.5, Apache-2.0 AND MIT AND Apache-2.0 AND MIT, approved, #4247 -crate/cratesio/-/itoa/1.0.5, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/lazy_static/1.4.0, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/libc/0.2.139, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/linefeed/0.6.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/log/0.4.17, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/matchers/0.1.0, MIT, approved, clearlydefined -crate/cratesio/-/memchr/2.5.0, Unlicense OR MIT, approved, clearlydefined -crate/cratesio/-/memoffset/0.6.5, MIT, approved, clearlydefined -crate/cratesio/-/mio/0.8.5, MIT, approved, clearlydefined -crate/cratesio/-/mortal/0.2.3, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/nix/0.23.2, MIT, approved, clearlydefined -crate/cratesio/-/nom/5.1.2, MIT, approved, clearlydefined -crate/cratesio/-/nu-ansi-term/0.46.0, MIT, approved, clearlydefined -crate/cratesio/-/num_cpus/1.15.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/once_cell/1.17.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/os_str_bytes/6.4.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/overload/0.1.1, MIT, approved, clearlydefined -crate/cratesio/-/percent-encoding/2.2.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/phf/0.11.1, MIT, approved, clearlydefined -crate/cratesio/-/phf_shared/0.11.1, MIT, approved, clearlydefined -crate/cratesio/-/pin-project-internal/1.0.12, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/pin-project-lite/0.2.9, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/pin-project/1.0.12, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/pin-utils/0.1.0, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/ppv-lite86/0.2.17, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/proc-macro2/1.0.50, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/prost-derive/0.9.0, Apache-2.0, approved, clearlydefined -crate/cratesio/-/prost-types/0.9.0, Apache-2.0, approved, clearlydefined -crate/cratesio/-/prost/0.9.0, Apache-2.0, approved, clearlydefined -crate/cratesio/-/quote/1.0.23, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/rand/0.8.5, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/rand_chacha/0.3.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/rand_core/0.6.4, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/redox_syscall/0.1.57, MIT, approved, clearlydefined -crate/cratesio/-/redox_syscall/0.2.16, MIT, approved, clearlydefined -crate/cratesio/-/redox_users/0.3.5, MIT, approved, clearlydefined -crate/cratesio/-/redox_users/0.4.3, MIT, approved, clearlydefined -crate/cratesio/-/regex-automata/0.1.10, MIT OR (MIT AND Unlicense), approved, clearlydefined -crate/cratesio/-/regex-syntax/0.6.28, Apache-2.0 AND MIT AND Apache-2.0 AND MIT AND Unicode-DFS-2016, approved, #4252 -crate/cratesio/-/regex/1.7.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/rust-argon2/0.8.3, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/ryu/1.0.12, Apache-2.0 AND BSL-1.0 AND CC-BY-SA-3.0, approved, #4267 -crate/cratesio/-/serde/1.0.152, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/serde_derive/1.0.152, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/serde_json/1.0.91, Apache-2.0 AND MIT, approved, #4264 -crate/cratesio/-/sharded-slab/0.1.4, MIT, approved, clearlydefined -crate/cratesio/-/signal-hook-registry/1.4.0, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/siphasher/0.3.10, Apache-2.0 AND MIT, approved, #6665 -crate/cratesio/-/slab/0.4.7, MIT, approved, clearlydefined -crate/cratesio/-/smallstr/0.2.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/smallvec/1.10.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/socket2/0.4.7, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/sqlparser/0.16.0, Apache-2.0, approved, #6669 -crate/cratesio/-/syn/1.0.107, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/terminfo/0.7.5, WTFPL AND X11-distribute-modifications-variant, approved, #6663 -crate/cratesio/-/textwrap/0.16.0, MIT, approved, #6657 -crate/cratesio/-/thiserror-impl/1.0.38, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/thiserror/1.0.38, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/thread_local/1.1.4, Apache-2.0 OR MIT, approved, clearlydefined -crate/cratesio/-/tinyvec/1.6.0, Zlib OR (Apache-2.0 OR MIT), approved, clearlydefined -crate/cratesio/-/tinyvec_macros/0.1.0, MIT OR (Apache-2.0 AND MIT) OR (MIT AND Zlib), approved, clearlydefined -crate/cratesio/-/tokio-io-timeout/1.2.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/tokio-macros/1.8.2, MIT, approved, clearlydefined -crate/cratesio/-/tokio-stream/0.1.11, MIT, approved, clearlydefined -crate/cratesio/-/tokio-util/0.6.10, MIT, approved, clearlydefined -crate/cratesio/-/tokio-util/0.7.4, MIT, approved, clearlydefined -crate/cratesio/-/tokio/1.24.2, MIT, approved, #6659 -crate/cratesio/-/tonic/0.6.2, MIT AND Apache-2.0, approved, #6653 -crate/cratesio/-/tower-layer/0.3.2, MIT, approved, clearlydefined -crate/cratesio/-/tower-service/0.3.2, MIT, approved, clearlydefined -crate/cratesio/-/tower/0.4.13, MIT AND Apache-2.0, approved, #6661 -crate/cratesio/-/tracing-attributes/0.1.23, MIT, approved, clearlydefined -crate/cratesio/-/tracing-core/0.1.30, MIT, approved, clearlydefined -crate/cratesio/-/tracing-futures/0.2.5, MIT, approved, clearlydefined -crate/cratesio/-/tracing-subscriber/0.3.16, MIT AND BSD-3-Clause AND BSD-2-Clause AND LicenseRef-Public-Domain, approved, #6670 -crate/cratesio/-/tracing/0.1.37, MIT, approved, clearlydefined -crate/cratesio/-/try-lock/0.2.4, MIT, approved, clearlydefined -crate/cratesio/-/unicode-ident/1.0.6, , approved, #4138 -crate/cratesio/-/unicode-normalization/0.1.22, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/unicode-width/0.1.10, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/want/0.3.0, MIT, approved, clearlydefined -crate/cratesio/-/wasi/0.11.0+wasi-snapshot-preview1, (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT), approved, #6667 -crate/cratesio/-/wasi/0.9.0+wasi-snapshot-preview1, (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT), approved, #6654 -crate/cratesio/-/winapi-i686-pc-windows-gnu/0.4.0, Apache-2.0 AND MIT, approved, #6664 -crate/cratesio/-/winapi-x86_64-pc-windows-gnu/0.4.0, Apache-2.0 AND MIT, approved, #6658 -crate/cratesio/-/winapi/0.3.9, Apache-2.0 AND MIT, approved, clearlydefined -crate/cratesio/-/windows-sys/0.42.0, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_aarch64_gnullvm/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_aarch64_msvc/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_i686_gnu/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_i686_msvc/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_x86_64_gnu/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_x86_64_gnullvm/0.42.1, MIT OR Apache-2.0, approved, clearlydefined -crate/cratesio/-/windows_x86_64_msvc/0.42.1, MIT OR Apache-2.0, approved, clearlydefined diff --git a/kuksa_databroker/Dockerfile b/kuksa_databroker/Dockerfile deleted file mode 100644 index badaa8297..000000000 --- a/kuksa_databroker/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -# /******************************************************************************** -# * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -# This is expected to be executed in the kuksa.val top-level directory -# You need to run build-all-targets.sh first, as this docker file jsut -# collects the artifacts - - -# Different targets need different base images, so prepare aliases here - -# AMD is a statically linked MUSL build -FROM scratch AS target-amd64 -ENV BUILDTARGET="x86_64-unknown-linux-musl" -COPY ./target/x86_64-unknown-linux-musl/release/databroker /app/databroker - - -# ARM64 is a statically linked GRPC build -FROM scratch AS target-arm64 -ENV BUILDTARGET="aarch64-unknown-linux-musl" -COPY ./target/aarch64-unknown-linux-musl/release/databroker /app/databroker - - -# RISCV is a glibc build. Rust toolchain not supported for MUSL -# Normally we prefer "distroless" base images, i.e.: -# FROM gcr.io/distroless/base-debian12:debug as target-riscv64 -# However, distorless has no RISCV support yet, -# (Nov 2023). Using debian unstable for now -FROM riscv64/debian:sid-slim as target-riscv64 - -ENV BUILDTARGET="riscv64gc-unknown-linux-gnu" -COPY ./target/riscv64gc-unknown-linux-gnu/release/databroker /app/databroker - -# Now adding generic parts -FROM target-$TARGETARCH as target -ARG TARGETARCH - -COPY ./dist/$TARGETARCH/thirdparty/ /app/thirdparty - -COPY ./data/vss-core/vss_release_3.1.1.json vss_release_3.1.1.json -COPY ./data/vss-core/vss_release_4.0.json vss_release_4.0.json - -ENV KUKSA_DATA_BROKER_ADDR=0.0.0.0 -ENV KUKSA_DATA_BROKER_PORT=55555 -ENV KUKSA_DATA_BROKER_METADATA_FILE=vss_release_4.0.json - -EXPOSE $KUKSA_DATA_BROKER_PORT - -ENTRYPOINT [ "/app/databroker" ] diff --git a/kuksa_databroker/Dockerfile-cli b/kuksa_databroker/Dockerfile-cli deleted file mode 100644 index 8b5b39193..000000000 --- a/kuksa_databroker/Dockerfile-cli +++ /dev/null @@ -1,58 +0,0 @@ -# /******************************************************************************** -# * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -# This is expected to be executed in the kuksa.val top-level directory -# You need to run build-all-targets-cli.sh first, as this docker file jsut -# collects the artifacts - -# AMD is a statically linked MUSL build -FROM scratch AS target-amd64 -ENV BUILDTARGET="x86_64-unknown-linux-musl" -COPY ./target/x86_64-unknown-linux-musl/release/databroker-cli /app/databroker-cli - - -# ARM64 is a statically linked GRPC build -FROM scratch AS target-arm64 -ENV BUILDTARGET="aarch64-unknown-linux-musl" -COPY ./target/aarch64-unknown-linux-musl/release/databroker-cli /app/databroker-cli - - -# RISCV is a glibc build. Rust toolchain not supported for MUSL -# Normally we prefer "distroless" base images, i.e.: -# FROM gcr.io/distroless/base-debian12:debug as target-riscv64 -# However, distorless has no RISCV support yet, -# (Nov 2023). Using debian unstable for now -FROM riscv64/debian:sid-slim as target-riscv64 -ENV BUILDTARGET="riscv64gc-unknown-linux-gnu" -COPY ./target/riscv64gc-unknown-linux-gnu/release/databroker-cli /app/databroker-cli - -# Databroker-cli is an interactive cli, thus it can only work correctly -# if we have some terminfo configurations available. We will transplant -# them from a donor -# While writing this, the latest versuion 3.18 does not support riscv yet, -# but edge does. As we are only getting some config files, this will -# likely not break -FROM alpine:edge as terminfo-donor -RUN apk update && apk add ncurses-terminfo-base - - -# Now adding generic parts -FROM target-$TARGETARCH as target -ARG TARGETARCH - -COPY ./dist/$TARGETARCH/thirdparty/ /app/thirdparty - -# Copy terminfo database -COPY --from=terminfo-donor /etc/terminfo /etc/terminfo - -ENTRYPOINT [ "/app/databroker-cli" ] diff --git a/kuksa_databroker/NOTICE.md b/kuksa_databroker/NOTICE.md deleted file mode 100644 index a1afa4d34..000000000 --- a/kuksa_databroker/NOTICE.md +++ /dev/null @@ -1,189 +0,0 @@ -## Declared Project Licenses - -This program and the accompanying materials are made available under the terms -of the Apache License 2.0 which is available at - - -SPDX-License-Identifier: Apache-2.0 - -## Contributors -* Robert Bosch GmbH - initial API and implementation -* Microsoft Corporation - initial API and implementation - -## Third-party Content - -| Dependency | Version | License | -|:-----------|:-------:|--------:| -|aho-corasick|0.7.18|MIT
Unlicense| -|ansi_term|0.12.1|MIT| -|anyhow|1.0.56|MIT OR Apache-2.0| -|arrayref|0.3.6|Simplified BSD| -|arrayvec|0.5.2|Apache 2.0
MIT| -|async-stream|0.3.2|MIT| -|async-stream-impl|0.3.2|MIT| -|async-trait|0.1.52|MIT OR Apache-2.0| -|autocfg|1.1.0|Apache-2.0 OR MIT| -|base64|0.13.0|Apache 2.0
MIT| -|bitflags|1.3.2|Apache 2.0
MIT| -|blake2b_simd|0.5.11|MIT| -|bytes|1.1.0|MIT| -|cc|1.0.73|Apache 2.0
MIT| -|cfg-if|0.1.10|Apache 2.0
MIT| -|cfg-if|1.0.0|Apache 2.0
MIT| -|clap|3.1.10|MIT OR Apache-2.0| -|clap_lex|0.1.1|MIT OR Apache-2.0| -|constant_time_eq|0.1.5|CC0-1.0| -|crossbeam-utils|0.8.7|MIT OR Apache-2.0| -|dirs|1.0.5|MIT OR Apache-2.0| -|dirs|2.0.2|MIT OR Apache-2.0| -|dirs-sys|0.3.6|MIT OR Apache-2.0| -|either|1.6.1|Apache 2.0
MIT| -|enum-iterator|0.7.0|BSD Zero Clause License| -|enum-iterator-derive|0.7.0|BSD Zero Clause License| -|fastrand|1.7.0|Apache-2.0 OR MIT| -|fixedbitset|0.4.1|Apache 2.0
MIT| -|fnv|1.0.7|MIT
Apache-2.0| -|form_urlencoded|1.0.1|Apache 2.0
MIT| -|futures-channel|0.3.21|MIT OR Apache-2.0| -|futures-core|0.3.21|MIT OR Apache-2.0| -|futures-sink|0.3.21|MIT OR Apache-2.0| -|futures-task|0.3.21|MIT OR Apache-2.0| -|futures-util|0.3.21|MIT OR Apache-2.0| -|getrandom|0.1.16|MIT OR Apache-2.0| -|getrandom|0.2.5|MIT OR Apache-2.0| -|getset|0.1.2|MIT| -|git2|0.14.0|Apache 2.0
MIT| -|h2|0.3.11|MIT| -|hashbrown|0.11.2|Apache 2.0
MIT| -|heck|0.3.3|MIT OR Apache-2.0| -|hermit-abi|0.1.19|Apache 2.0
MIT| -|http|0.2.6|Apache 2.0
MIT| -|http-body|0.4.4|MIT| -|httparse|1.6.0|Apache 2.0
MIT| -|httpdate|1.0.2|Apache 2.0
MIT| -|hyper|0.14.17|MIT| -|hyper-timeout|0.4.1|Apache 2.0
MIT| -|idna|0.2.3|Apache 2.0
MIT| -|indexmap|1.8.0|Apache 2.0
MIT| -|instant|0.1.12|New BSD| -|itertools|0.10.3|Apache 2.0
MIT| -|itoa|1.0.1|MIT OR Apache-2.0| -|jobserver|0.1.24|Apache 2.0
MIT| -|lazy_static|1.4.0|Apache 2.0
MIT| -|libc|0.2.119|MIT OR Apache-2.0| -|libgit2-sys|0.13.0+1.4.1|Apache 2.0
MIT| -|libz-sys|1.1.3|MIT OR Apache-2.0| -|linefeed|0.6.0|Apache 2.0
MIT| -|log|0.4.14|MIT OR Apache-2.0| -|matchers|0.1.0|MIT| -|matches|0.1.9|MIT| -|memchr|2.4.1|MIT
Unlicense| -|mio|0.8.0|MIT| -|miow|0.3.7|Apache 2.0
MIT| -|mortal|0.2.2|Apache 2.0
MIT| -|multimap|0.8.3|Apache 2.0
MIT| -|nix|0.17.0|MIT| -|nom|5.1.2|MIT| -|ntapi|0.3.7|Apache-2.0 OR MIT| -|num_cpus|1.13.1|MIT OR Apache-2.0| -|num_threads|0.1.5|MIT OR Apache-2.0| -|once_cell|1.9.0|MIT OR Apache-2.0| -|os_str_bytes|6.0.0|MIT OR Apache-2.0| -|percent-encoding|2.1.0|Apache 2.0
MIT| -|petgraph|0.6.0|Apache 2.0
MIT| -|phf|0.8.0|MIT| -|phf_codegen|0.8.0|MIT| -|phf_generator|0.8.0|MIT| -|phf_shared|0.8.0|MIT| -|pin-project|1.0.10|Apache-2.0 OR MIT| -|pin-project-internal|1.0.10|Apache-2.0 OR MIT| -|pin-project-lite|0.2.8|Apache-2.0 OR MIT| -|pin-utils|0.1.0|MIT OR Apache-2.0| -|pkg-config|0.3.24|Apache 2.0
MIT| -|ppv-lite86|0.2.16|Apache 2.0
MIT| -|proc-macro-error|1.0.4|MIT OR Apache-2.0| -|proc-macro-error-attr|1.0.4|MIT OR Apache-2.0| -|proc-macro2|1.0.36|MIT OR Apache-2.0| -|prost|0.9.0|Apache 2.0| -|prost-build|0.9.0|Apache 2.0| -|prost-derive|0.9.0|Apache 2.0| -|prost-types|0.9.0|Apache 2.0| -|quote|1.0.15|MIT OR Apache-2.0| -|rand|0.7.3|MIT OR Apache-2.0| -|rand|0.8.5|MIT OR Apache-2.0| -|rand_chacha|0.2.2|MIT OR Apache-2.0| -|rand_chacha|0.3.1|MIT OR Apache-2.0| -|rand_core|0.5.1|MIT OR Apache-2.0| -|rand_core|0.6.3|MIT OR Apache-2.0| -|rand_hc|0.2.0|Apache 2.0
MIT| -|rand_pcg|0.2.1|MIT OR Apache-2.0| -|redox_syscall|0.1.57|MIT| -|redox_syscall|0.2.10|MIT| -|redox_users|0.3.5|MIT| -|redox_users|0.4.0|MIT| -|regex|1.5.4|MIT OR Apache-2.0| -|regex-automata|0.1.10|MIT
Unlicense| -|regex-syntax|0.6.25|Apache 2.0
MIT| -|remove_dir_all|0.5.3|Apache 2.0
MIT| -|rust-argon2|0.8.3|Apache 2.0
MIT| -|rustversion|1.0.6|MIT OR Apache-2.0| -|ryu|1.0.9|Apache-2.0 OR BSL-1.0| -|serde|1.0.137|MIT OR Apache-2.0| -|serde_json|1.0.81|MIT OR Apache-2.0| -|sharded-slab|0.1.4|MIT| -|signal-hook-registry|1.4.0|Apache 2.0
MIT| -|siphasher|0.3.9|Apache 2.0
MIT| -|slab|0.4.5|MIT| -|smallstr|0.2.0|Apache 2.0
MIT| -|smallvec|1.8.0|Apache 2.0
MIT| -|socket2|0.4.4|MIT OR Apache-2.0| -|sqlparser|0.16.0|Apache 2.0| -|syn|1.0.86|MIT OR Apache-2.0| -|tempfile|3.3.0|MIT OR Apache-2.0| -|terminfo|0.7.3|WTFPL| -|textwrap|0.15.0|MIT| -|thiserror|1.0.30|MIT OR Apache-2.0| -|thiserror-impl|1.0.30|MIT OR Apache-2.0| -|thread_local|1.1.4|Apache 2.0
MIT| -|time|0.3.9|MIT OR Apache-2.0| -|tinyvec|1.5.1|Zlib OR Apache-2.0 OR MIT| -|tinyvec_macros|0.1.0|MIT OR Apache-2.0 OR Zlib| -|tokio|1.17.0|MIT| -|tokio-io-timeout|1.2.0|Apache 2.0
MIT| -|tokio-macros|1.7.0|MIT| -|tokio-stream|0.1.8|MIT| -|tokio-util|0.6.9|MIT| -|tokio-util|0.7.0|MIT| -|tonic|0.6.2|MIT| -|tonic-build|0.6.2|MIT| -|tower|0.4.12|MIT| -|tower-layer|0.3.1|MIT| -|tower-service|0.3.1|MIT| -|tracing|0.1.34|MIT| -|tracing-attributes|0.1.20|MIT| -|tracing-core|0.1.22|MIT| -|tracing-futures|0.2.5|MIT| -|tracing-subscriber|0.3.11|MIT| -|try-lock|0.2.3|MIT| -|unicode-bidi|0.3.7|Apache-2.0
MIT| -|unicode-normalization|0.1.19|Apache 2.0
MIT| -|unicode-segmentation|1.9.0|Apache 2.0
MIT| -|unicode-width|0.1.9|Apache 2.0
MIT| -|unicode-xid|0.2.2|MIT OR Apache-2.0| -|url|2.2.2|Apache 2.0
MIT| -|valuable|0.1.0|MIT| -|vcpkg|0.2.15|Apache 2.0
MIT| -|databroker-api|0.17.0|Apache 2.0| -|databroker|0.17.0|Apache 2.0| -|databroker-cli|0.17.0|Apache 2.0| -|databroker-examples|0.17.0|Apache 2.0| -|vergen|7.0.0|MIT OR Apache-2.0| -|version_check|0.9.4|Apache 2.0
MIT| -|void|1.0.2|MIT| -|want|0.3.0|MIT| -|wasi|0.10.2+wasi-snapshot-preview1|Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT| -|wasi|0.9.0+wasi-snapshot-preview1|Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT| -|which|4.2.4|MIT| -|winapi|0.3.9|Apache 2.0
MIT| -|winapi-i686-pc-windows-gnu|0.4.0|Apache 2.0
MIT| -|winapi-x86_64-pc-windows-gnu|0.4.0|Apache 2.0
MIT| diff --git a/kuksa_databroker/README.md b/kuksa_databroker/README.md deleted file mode 100644 index 027c8de83..000000000 --- a/kuksa_databroker/README.md +++ /dev/null @@ -1,267 +0,0 @@ -![Rust](https://img.shields.io/badge/rust-000000.svg?style=for-the-badge&logo=rust&logoColor=white)![Docker](https://img.shields.io/badge/docker-1D63ED.svg?style=for-the-badge&logo=docker&logoColor=white) - - -**The KUKSA Databroker has been moved to a [new repository](https://github.com/eclipse-kuksa/kuksa-databroker)!** - -*Use this repository only for accessing older versions!* - - - - - -
-
- - Logo - - -

Eclipse Kuksa.val™ Databroker

- -

- Kuksa.val Databroker is a gRPC service acting as a broker of vehicle data / data points / signals. -
- Explore the docs » -
-
- Report Bug - · - Request Feature - · - Chat -

-
- - -
- Table of Contents -
    -
  1. - Intro - -
  2. -
  3. - Getting Started - -
  4. -
  5. Usage
  6. -
  7. Building
  8. -
  9. Roadmap
  10. -
  11. Contributing
  12. -
  13. License
  14. -
  15. Contact
  16. -
-
- - -## Intro - -The [COVESA Vehicle Signal Specification](https://covesa.github.io/vehicle_signal_specification/) (VSS) defines the names and semantics of a large set of *data entries* that represent the current and/or intended state of a vehicle's sensors and actuators organized in a tree-like structure. For example, the vehicle's current speed is represented by the `Vehicle.Speed` entry. - -However, VSS does not define how these signals are to be collected and managed within a vehicle, nor does it prescribe how other components in the vehicle can read or write signal values from and to the tree. - -**Kuksa.val Databroker** is a resource efficient implementation of the VSS signal tree and is intended to be run within a vehicle on a microprocessor based platform. It allows applications in the vehicle to interact with the vehicle's sensors and actuators using a uniform, high level gRPC API for querying signals, updating current and target values of sensors and actuators and getting notified about changes to signals of interest. - - - -```mermaid -flowchart LR - A[Application] --VSS--- DB - DB[Kuksa.val Databroker] --VSS--- P - P[Kuksa.val Provider] --CAN frames etc---E - E[ECU] --- Sensor - E --- Actuator - style DB fill:#999999,stroke:#444444,color:#ffffff -``` - -At the right end, [Kuksa.val Providers](https://github.com/eclipse/kuksa.val.feeders) implement the link between the Databroker and a vehicle's Electronic Control Units (ECU) to which the hardware sensors and actuators are physically attached. - -Data is usually exchanged with ECUs by means of a CAN bus or Ethernet based protocols like SOME/IP. Providers translate between the low level messages used by these protocols and the Databroker's high level gRPC API calls to update a sensor's current reading or to forward a set-point value to an actuator via its controlling ECU. - -

(back to top)

- -### Features - -- 100% Open Source (Apache 2.0 license) -- Written in Rust with an easy-to-use language agnostic gRPC interface -- Lightweight (<4 MB statically compiled), allowing it to run on even small vehicle computers - -

(back to top)

- - -## Getting started - -The quickest possible way to get Kuksa.val Databroker up and running. - -> :memo: **Note:** The examples in this section do not use TLS nor access control. Please refer to the [User Guide](./doc/user_guide.md) for more sophisticated usage examples. - -### Prerequisites - -* [Docker Engine](https://docs.docker.com/engine/install/) or [Podman](https://podman.io/docs/installation) -* A custom Docker *bridge* network - ```sh - docker network create kuksa - ``` - -### Starting Databroker - -1. Start Databroker in a container attached to the *kuksa* bridge network using hostname *Server*: - - ```sh - docker run -it --rm --name Server --network kuksa ghcr.io/eclipse/kuksa.val/databroker:master --insecure - ``` - > :bulb: **Tip:** You can stop the container using `ctrl-c`. - -### Reading and writing VSS data using the CLI - -1. Start the CLI in a container attached to the *kuksa* bridge network and connect to the Databroker container: - The databroker supports both of ```sdv.databroker.v1``` and ```kuksa.val.v1``` as an API. Per default the databroker-cli uses the ```sdv.databroker.v1``` interface. To change it use ```--protocol``` option when starting. Chosse eihter one of ```kuksa-val-v1``` and ```sdv-databroker-v1```. - - - ```sh - # in a new terminal - docker run -it --rm --network kuksa ghcr.io/eclipse/kuksa.val/databroker-cli:master --server Server:55555 - ``` - - The CLI provides an interactive prompt which can be used to send commands to the Databroker. - - ```console - ⠀⠀⠀⢀⣤⣶⣾⣿⢸⣿⣿⣷⣶⣤⡀ - ⠀⠀⣴⣿⡿⠋⣿⣿⠀⠀⠀⠈⠙⢿⣿⣦ - ⠀⣾⣿⠋⠀⠀⣿⣿⠀⠀⣶⣿⠀⠀⠙⣿⣷ - ⣸⣿⠇⠀⠀⠀⣿⣿⠠⣾⡿⠃⠀⠀⠀⠸⣿⣇⠀⠀⣶⠀⣠⡶⠂⠀⣶⠀⠀⢰⡆⠀⢰⡆⢀⣴⠖⠀⢠⡶⠶⠶⡦⠀⠀⠀⣰⣶⡀ - ⣿⣿⠀⠀⠀⠀⠿⢿⣷⣦⡀⠀⠀⠀⠀⠀⣿⣿⠀⠀⣿⢾⣏⠀⠀⠀⣿⠀⠀⢸⡇⠀⢸⡷⣿⡁⠀⠀⠘⠷⠶⠶⣦⠀⠀⢠⡟⠘⣷ - ⢹⣿⡆⠀⠀⠀⣿⣶⠈⢻⣿⡆⠀⠀⠀⢰⣿⡏⠀⠀⠿⠀⠙⠷⠄⠀⠙⠷⠶⠟⠁⠀⠸⠇⠈⠻⠦⠀⠐⠷⠶⠶⠟⠀⠠⠿⠁⠀⠹⠧ - ⠀⢿⣿⣄⠀⠀⣿⣿⠀⠀⠿⣿⠀⠀⣠⣿⡿ - ⠀⠀⠻⣿⣷⡄⣿⣿⠀⠀⠀⢀⣠⣾⣿⠟ databroker-cli - ⠀⠀⠀⠈⠛⠇⢿⣿⣿⣿⣿⡿⠿⠛⠁ v0.4.1 - - Successfully connected to http://Server:55555/ - sdv.databroker.v1 > - ``` - > :bulb: **Tip:** The client retrieves metadata about the data entries that the Databroker knows about during startup. This allows for using `TAB`-completion of data entry names at the prompt. - -1. Display help for supported commands - ```sh - help - ``` - ```console - connect [URI] Connect to server - get [[PATH] ...] Get signal value(s) - set Set actuator signal - subscribe Subscribe to signals with QUERY - feed Publish signal value - metadata [PATTERN] Fetch metadata. Provide PATTERN to list metadata of signals matching pattern. - token Use TOKEN as access token - token-file Use content of FILE as access token - help You're looking at it. - quit Quit - ``` -1. Get the vehicle's current speed - - ```sh - get Vehicle.Speed - ``` - ```console - [get] OK - Vehicle.Speed: ( NotAvailable ) - ``` - > :memo: **Note** When Databroker starts up, all data entries are initialized to empty values. Thus, the vehicle speed is being reported as `NotAvailable`. - -2. Set the vehicle's current speed - - ```sh - feed Vehicle.Speed 100.34 - ``` - ```console - [set] OK - ``` - -3. Get the vehicle's current speed - - ```sh - get Vehicle.Speed - ``` - ```console - [get] OK - Vehicle.Speed: 100.34 - ``` - -Run the cli with: - -4. Exit the client - ```sh - quit - ``` - -

(back to top)

- - - -## Usage - -Please refer to the [User Guide](./doc/user_guide.md) for details regarding how to run and interact with Kuksa.val Databroker. - -

(back to top)

- -## Building - -Building Kuksa.val Databroker from source code requires - -* a [Rust tool chain](https://www.rust-lang.org/tools/install) -* a local workspace containing the source code - ```shell - git clone https://github.com/eclipse/kuksa.val.git - ``` - -

(back to top)

- -### Building Examples and Binaries - -```sh -# in ${WORKSPACE} -cargo build --examples --bins -``` - -

(back to top)

- -### Building release Binaries - -```sh -# in ${WORKSPACE} -cargo build --bins --release -``` - -

(back to top)

- -### Runing Databroker Test Cases - -```shell -# in ${WORKSPACE} -cargo test --all-targets -``` - -

(back to top)

- -## Contributing - -Please refer to the [Kuksa.val Contributing Guide](../CONTRIBUTING.md). - -

(back to top)

- -## License - -Kuksa.val Databroker is provided under the terms of the [Apache Software License 2.0](../LICENSE). - -

(back to top)

- -## Contact - -Please feel free to create [GitHub Issues](https://github.com/eclipse/kuksa.val/issues) for reporting bugs and/or ask questions in our [Gitter chat room](https://matrix.to/#/#kuksa-val_community:gitter.im). - -

(back to top)

diff --git a/kuksa_databroker/build-all-targets-cli.sh b/kuksa_databroker/build-all-targets-cli.sh deleted file mode 100755 index 341ad631a..000000000 --- a/kuksa_databroker/build-all-targets-cli.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# Building all currently supported targets for databroker-cli. -# Uses cross for cross-compiling. Needs to be executed -# before docker build, as docker collects the artifacts -# created by this script -# this needs the have cross, cargo-license and createbom dependencies installed -# -# SPDX-License-Identifier: Apache-2.0 - - -# exit on error, to not waste any time -set -e - -CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse - -# Create thirdparty bom -cd createbom/ -rm -rf ../databroker/thirdparty || true -python3 createbom.py ../databroker-cli -cd .. - -# Starting a fresh build -echo "Cargo clean, to start fresh..." -cargo clean -rm -rf ../dist || true -mkdir ../dist - -# Buidling AMD46 -echo "Building AMD64" -cross build --target x86_64-unknown-linux-musl --bin databroker-cli --release -# We need to clean this folder in target, otherwise we get weird side -# effects building the aarch image, complaining libc crate can not find -# GLIBC, i.e -# Compiling libc v0.2.149 -#error: failed to run custom build command for `libc v0.2.149` -# -#Caused by: -# process didn't exit successfully: `/target/release/build/libc-2dd22ab6b5fb9fd2/#build-script-build` (exit status: 1) -# --- stderr -# /target/release/build/libc-2dd22ab6b5fb9fd2/build-script-build: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.29' not found (required by /target/release/build/libc-2dd22ab6b5fb9fd2/build-script-build) -# -# It seems cross/cargo is reusing something from previous builds it shouldn't. -# the finished artifact resides in ../target/x86_64-unknown-linux-musl/release -# so deleting the temporary files in trget/releae is no problem -echo "Cleaning up...." -rm -rf ../target/release - - -# Buidling ARM64 -echo "Building ARM64" -cross build --target aarch64-unknown-linux-musl --bin databroker-cli --release -echo "Cleaning up...." -rm -rf ../target/release - - -# Build RISCV64, this is a glibc based build, as musl is not -# yet supported -echo "Building RISCV64" -cross build --target riscv64gc-unknown-linux-gnu --bin databroker-cli --release -echo "Cleaning up...." -rm -rf ../target/release - -# Prepare dist folders -echo "Prepare amd64 dist folder" -mkdir ../dist/amd64 -cp ../target/x86_64-unknown-linux-musl/release/databroker-cli ../dist/amd64 -cp -r ./databroker-cli/thirdparty ../dist/amd64 - -echo "Prepare arm64 dist folder" -mkdir ../dist/arm64 -cp ../target/aarch64-unknown-linux-musl/release/databroker-cli ../dist/arm64 -cp -r ./databroker-cli/thirdparty ../dist/arm64 - -echo "Prepare riscv64 dist folder" -mkdir ../dist/riscv64 -cp ../target/riscv64gc-unknown-linux-gnu/release/databroker-cli ../dist/riscv64 -cp -r ./databroker-cli/thirdparty ../dist/riscv64 diff --git a/kuksa_databroker/build-all-targets.sh b/kuksa_databroker/build-all-targets.sh deleted file mode 100755 index b5d72b746..000000000 --- a/kuksa_databroker/build-all-targets.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# Building all currently supported targets. -# Uses cross for cross-compiling. Needs to be executed -# before docker build, as docker collects the artifacts -# created by this script -# this needs the have cross, cargo-license and createbom dependencies installed -# -# SPDX-License-Identifier: Apache-2.0 - -# exit on error, to not waste any time -set -e - -CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse - -# Create thirdparty bom -cd createbom/ -rm -rf ../databroker/thirdparty || true -python3 createbom.py ../databroker -cd .. - -# Starting a fresh build -echo "Cargo clean, to start fresh..." -cargo clean -rm -rf ../dist || true -mkdir ../dist - -# Buidling AMD46 -echo "Building AMD64" -cross build --target x86_64-unknown-linux-musl --bin databroker --release -# We need to clean this folder in target, otherwise we get weird side -# effects building the aarch image, complaining libc crate can not find -# GLIBC, i.e -# Compiling libc v0.2.149 -#error: failed to run custom build command for `libc v0.2.149` -# -#Caused by: -# process didn't exit successfully: `/target/release/build/libc-2dd22ab6b5fb9fd2/#build-script-build` (exit status: 1) -# --- stderr -# /target/release/build/libc-2dd22ab6b5fb9fd2/build-script-build: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.29' not found (required by /target/release/build/libc-2dd22ab6b5fb9fd2/build-script-build) -# -# It seems cross/cargo is reusing something from previous builds it shouldn't. -# the finished artifact resides in ../target/x86_64-unknown-linux-musl/release -# so deleting the temporary files in trget/releae is no problem -echo "Cleaning up...." -rm -rf ../target/release - - -# Buidling ARM64 -echo "Building ARM64" -cross build --target aarch64-unknown-linux-musl --bin databroker --release -echo "Cleaning up...." -rm -rf ../target/release - - -# Build RISCV64, this is a glibc based build, as musl is not -# yet supported -echo "Building RISCV64" -cross build --target riscv64gc-unknown-linux-gnu --bin databroker --release -echo "Cleaning up...." -rm -rf ../target/release - -# Prepare dist folders -echo "Prepare amd64 dist folder" -mkdir ../dist/amd64 -cp ../target/x86_64-unknown-linux-musl/release/databroker ../dist/amd64 -cp -r ./databroker/thirdparty ../dist/amd64 - -echo "Prepare arm64 dist folder" -mkdir ../dist/arm64 -cp ../target/aarch64-unknown-linux-musl/release/databroker ../dist/arm64 -cp -r ./databroker/thirdparty ../dist/arm64 - -echo "Prepare riscv64 dist folder" -mkdir ../dist/riscv64 -cp ../target/riscv64gc-unknown-linux-gnu/release/databroker ../dist/riscv64 -cp -r ./databroker/thirdparty ../dist/riscv64 diff --git a/kuksa_databroker/createbom/README.md b/kuksa_databroker/createbom/README.md deleted file mode 100644 index 874585ace..000000000 --- a/kuksa_databroker/createbom/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# BOM Generator - -Generates a BOM - -## Troubleshooting - -If you run it and you get errors like: - -``` -Could not find license file for 0BSD in adler -Error: BOM creation failed, unresolved licenses detected -``` - -The a possible reason is that the `Cargo.lock` in the repository has been updated and some components use licenses -not covered here. This can be solved by: - -* Find the corresponding license test. Check for instance [SPDX](https://spdx.org/licenses/) -* Verify that license is feasible for our use. -* Download or create a text file with the license text, do `gzip` and put it in `licensestore` folder. -* Add the identifier (in the example above `0BSD`) to `maplicensefile.py` diff --git a/kuksa_databroker/createbom/bomutil/maplicensefile.py b/kuksa_databroker/createbom/bomutil/maplicensefile.py deleted file mode 100644 index 044f587d1..000000000 --- a/kuksa_databroker/createbom/bomutil/maplicensefile.py +++ /dev/null @@ -1,40 +0,0 @@ -#! /usr/bin/env python -######################################################################## -# Copyright (c) 2022, 2023 Robert Bosch GmbH -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -######################################################################## - -"""Mapping of license identifiers of cargo license to the filenames of the actual license texts.""" - -MAP = { - "Apache-2.0": "Apache-2.0.txt.gz", - "BlueOak-1.0.0": "BlueOak-1.0.0.md.gz", - "MIT": "MIT.txt.gz", - "Unlicense": "Unlicense.txt.gz", - "BSL-1.0": "BSL-1.0.txt.gz", - "Unicode-DFS-2016": "Unicode-DFS-2016.txt.gz", - "BSD-2-Clause": "BSD-2-Clause.txt.gz", - "CC0-1.0": "CC0-1.0.txt.gz", - "WTFPL": "WTFPL.txt.gz", - "Zlib": "Zlib.txt.gz", - "ISC": "ISC.txt.gz", - "ring": "ring.LICENSE.txt.gz", - "rustls-webpki": "webpki.LICENSE.txt.gz", - # License text taken from https://spdx.org/licenses/0BSD.html - "0BSD": "0BSD.txt.gz", - # License test taken from https://spdx.org/licenses/BSD-3-Clause.html - "BSD-3-Clause": "BSD-3-Clause.txt.gz" -} diff --git a/kuksa_databroker/createbom/bomutil/quirks.py b/kuksa_databroker/createbom/bomutil/quirks.py deleted file mode 100644 index 70df6fa29..000000000 --- a/kuksa_databroker/createbom/bomutil/quirks.py +++ /dev/null @@ -1,36 +0,0 @@ -#! /usr/bin/env python -######################################################################## -# Copyright (c) 2022, 2023 Robert Bosch GmbH -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -######################################################################## - -'''Hook for applying some sanitation to make further processing easier''' - -def apply_quirks(component): - ''' - Takes one component entry from cargo license and might return - a modified/extended entry. - Use sparingly. Comment what you are doing - Use narrow matching (name and complete license string) to catch - changes - ''' - if component["name"] in {"io-lifetimes", "linux-raw-sys", "rustix", "wasi"} \ - and component["license"] == "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT": - # All licenses are "OR", we already ship Apache-2.0 and MIT. The LLVM exception - # does not apply to us, so lets keep it clean. - component["license"] = "Apache-2.0 OR MIT" - return component - return component diff --git a/kuksa_databroker/createbom/createbom.py b/kuksa_databroker/createbom/createbom.py deleted file mode 100644 index 4785195fd..000000000 --- a/kuksa_databroker/createbom/createbom.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env python3 -######################################################################## -# Copyright (c) 2022,2023 Robert Bosch GmbH -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -######################################################################## - -""" -This script will generate a list of all dependencies and licenses of a -Rust project. It will create a folder called thirdparty in that -project folder containing a list of dependencies and a copy -of each license used in dependencies -""" - -import argparse -import sys -import json -import re -import os -import gzip - -from subprocess import check_output, CalledProcessError - -from bomutil.maplicensefile import MAP as supported_licenses -from bomutil import quirks - - -class LicenseException(Exception): - pass - - -class RunCargoException(Exception): - pass - - -def extract_license_ids(license): - """Extract valid licenses for each dependency. We most of the time - do not care whether it is "AND" or "OR" currently, we currently assume we are - compatible to all "OR" variants, and thus include all""" - license_ids = [] - if license: - license_ids = re.split(r"\s*AND\s*|\s*OR\s*|\(|\)", license) - license_ids = list(filter(None, license_ids)) - - return license_ids - - -def extract_license_filenames(crate): - license_files = [] - crate = quirks.apply_quirks(crate) - - crate_name = crate["name"] - license_ids = extract_license_ids(crate["license"]) - license_file = crate["license_file"] - - if not license_ids and not license_file: - raise LicenseException( - f"Neither license nor license file specified for {crate_name}" - ) - - if license_file: - license_ids.append(crate_name) - - missing = [] - for license_id in license_ids: - if license_id in supported_licenses: - license_file = supported_licenses[license_id] - license_files.append(license_file) - else: - missing.append(license_id) - - if missing: - missing_licenses = ", ".join(missing) - raise LicenseException( - f"Could not find license file for {missing_licenses} in {crate_name}" - ) - - return license_files - - -def generate_bom(source_path, target_path, dashout): - try: - cargo_output = check_output( - [ - "cargo", - "license", - "--json", - "--avoid-build-deps", - "--current-dir", - source_path, - ] - ) - except CalledProcessError as e: - raise RunCargoException(f"Error running cargo license: {e}") - - crates = json.loads(cargo_output) - dashlist = [] - - # Cargo will also pick up our own dependencies. As they are not thirdparty - # creating a new list without our own packages - crates = [ - crate for crate in crates if not crate["name"].startswith("databroker") - and not crate["name"].startswith("kuksa") - ] - - license_files = set() - errors = [] - for crate in crates: - try: - print(f"License for {crate['name']} {crate['version']}: ", end="") - license_filenames = extract_license_filenames(crate) - for license_filename in license_filenames: - license_files.add(license_filename) - unpacked_filenames = [ - filename[:-3] if filename.endswith(".gz") else filename - for filename in license_filenames - ] - print(" ".join(unpacked_filenames)) - del crate["license_file"] - crate["license_files"] = unpacked_filenames - dashlist.append( - f"crate/cratesio/-/{crate['name']}/{crate['version']}") - except LicenseException as e: - errors.append(e) - - if errors: - for error in errors: - print(error) - raise LicenseException( - "BOM creation failed, unresolved licenses detected") - - # Exporting - os.mkdir(target_path) - - for license_file in license_files: - print(f"Copying {license_file[:-2]}") - with gzip.open("licensestore/" + license_file, "rb") as inf: - content = inf.read() - with open(os.path.join(target_path, license_file[:-3]), "wb") as outf: - outf.write(content) - - print("Writing thirdparty_components.txt") - with open( - os.path.join(target_path, "thirdparty_components.txt"), "w", encoding="utf-8" - ) as jsonout: - json.dump(crates, jsonout, indent=4) - - if dashout is not None: - print(f"Exporting dash output to {dashout}") - with open(dashout, 'w') as f: - for line in dashlist: - f.write(f"{line}\n") - - -def main(args=None): - parser = argparse.ArgumentParser() - parser.add_argument("dir", help="Rust project directory") - parser.add_argument("--dash", default=None, type=str, - help="if present, write an input file for dash PATH", metavar="PATH") - args = parser.parse_args(args) - - source_path = os.path.abspath(args.dir) - target_path = os.path.join(source_path, "thirdparty") - - if os.path.exists(target_path): - print( - f"Folder {target_path} already exists. Remove it before running this script." - ) - return -2 - - if args.dash is not None and os.path.exists(args.dash): - print( - f"Requested Dash output file {args.dash} exists. Remove it before running this script.") - return -3 - - print(f"Generating BOM for project in {source_path}") - try: - generate_bom(source_path, target_path, args.dash) - except LicenseException as e: - print(f"Error: {e}") - return -100 - except RunCargoException as e: - print(f"Error: {e}") - return -1 - - -if __name__ == "__main__": - - sys.exit(main(sys.argv[1:])) diff --git a/kuksa_databroker/createbom/licensestore/0BSD.txt.gz b/kuksa_databroker/createbom/licensestore/0BSD.txt.gz deleted file mode 100644 index d6b2a6dc9572d57e6c9a2289bd26c7671ac812a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmV;C0dD>uiwFoYFv4U21295UL@soAbO2S5QE#I#5QN|JD@J`rx!1~+jVZ34)ai3FxKjZCD;B7n&XFZSC)30&D zX_%L3c)c$P%Vn4`kLTt6I3=9*=kfZ$?LOVcIpKX+F3@lJ9PbOxDM9s@G^N)E{!Yj1 zl1|&rCbkUmbv#gD7{NaHXH#*7ClZ~XK(0a-Q6F0$P#GyLnNC2~La9J58WtQ(Y!SGj zpn9)}n*B3&rR^)@nw2u$-WrYgLHimVhqBd?cE+0cvIf^CIu_Zg0h|Xvvx|^6oBZgs zV^~8w%cylC_X62-X~-5@H*gsX<-gxlQFSp`w5$}$u~rMYG3irA<6Ty3XbhAaIBu+I*p-|?zpA4TD(vM8 vC_uqTPV{}uv|kO?!||u%y6(IKZL#Ka(93tUy4L@%f4lhr2J-0|UjhICY`4dF diff --git a/kuksa_databroker/createbom/licensestore/Apache-2.0.txt.gz b/kuksa_databroker/createbom/licensestore/Apache-2.0.txt.gz deleted file mode 100644 index 43305c2eb64f5cfea476fbb3f65a5a57a131d446..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3977 zcmV;44|eb$iwFoQjcQ{613_?MV`ybEE_8Tw0Nq+!bKAxhe$TJia;8&h2Bw``+c-~* zB`0hhN+Zg3GnqUrfd#oWfJJrzQS7hpx$F%jCA-tNYBH@!V$YsEm+yS%EQI*P-=df0 zPKkHARGm{_JoDr~ly%y4;;Z?qLi|m3qqGO{)vH(EJh^B$4E^huFZcWXT+%jkW4A9G z-palF0vFz2-~GH6i`A8QbF;cy-Y;)fYw`BxPP|`V7vk>v_U`8D{Tuwcpr@{u>-)Rq z5AX3C67c0*T&Y@jdI06z{0pzm%%5l`+)g%)XqD{504E)kZJm%^B}&s(yh_x@iqWY; zSk+rojU|3vcv1LlrQKllX2kD>bfUs7RV6kDu~sDu`4Z$?Gj4a{J7H@0py4@Fj;-p3 zW4(+$QLHrm!Rqa95N6*gD?lY!sE31)DEeE*lp<{Z--0) zwUv#yCebHKj2#}3v{yowBqeA8W`JkC7y}P@1+{X#H5hcTrYVH9Dtu^2=>kuK-;P}c z%SzL>rt^~ggJQ3T9n0Yj=i;rgq(?v6-ay18t44u?F^WQ4Ic!JgB!r==mT(*RW3*bksH;45lRiN zoJh~~OfLV$j5BcoYw=%pcA0w}{zIEQ=xRh+R^;*F1*k{RRy$M#^lr6t6z~*hoCM^S zlTcg3ZY883q*r?!X}wjovKE%puQgfxBW}@}O2g44WmRyn?#gB)Q$P}m&J3c_t;XHK zkIvM?9>dGghTxP6tRHfZ1bH$1KoRo4*4xq2@8Fh3W$6W5OYfw3Gt63&)5Fz^3!ZYGnmL z@*s61H%-X@43`Q-Qw+dT`cRS)7XrG08Q|dvZ)_=eSd&@hFko#V3k7YxhzmG?dX#Ms zJHtYNb_jD`h)*v1Uct_fkW7u)UnVPDDXSmAiVsSlLEP*(0&tJ>Ht?tSlGp}8@r`uo zypB?_!aXqhA$l0Aa4T{b=E8ob%UuQr;H&{^0A!|B51L$wQ4FT>c_I{8*x2w1M0hvn z+2n;`l~WEPg{&`OGt*E~z%sqn9qe-I^HV$yI8{&5zYxdf^VY*?_P!(WzG_(2N*(i4 z_0m$Lpk3$~t+J{)Kpu1-$#5Hp7L1clw(2rCT>}u=T9#BKimXOPqn;>*)={QTUVnp7 z?rZ#6k00kiOxbL|Xh5HEp_WEHP}syL6vLHgB0-X2+t4cb{VC;(EGY&=eFIxJ0k++^ z0qpSL5qJkh7imuF`Bb2d2**!oMes6}yJxFKPE-(;X?u+KjRIrVV2Y>7%jZ>lF^gxK zd0AZVBP_!r)j$GT17KXB7dEn?INDoW*Ae*`J8yk~S&$oDB}1W|2A7hB?C*+aOHstG zd=L09=>&+V8(iD~r37hN$%<6S9o(Q=mqR$z+)-f(DXB*KC)oX1`IxOlu9X|T$Y5j= z1(~(cZoqNN(NUGB9b3XnPa{7N;-%809)l64XASWPM{&I_M>9G|-d5U=2z@rOqd>Wo z)7y@)A3_m*M20;Zi3nD+71&#fJXhzl(-c19*YVgP13yW5aswhhwnv+a9VoL=5KllE z6(Kn&o$r&9(5c@?h@S?xEe+V4%QX_-Ed3aWzM6|4kyhchZ{qO-vl8o(i>r^-v&~GF zW;rS=sFETxkU$6lor%Q}F931~rv!%As{t$%!VjRYsrDMVMrXPg7wL$?JhAjf));}fJyaNds_SPNE!KD;uf7-u!HKIItoK$*mi4vxDq)PFhXbSzAD#(9tLzYG0oC z7w!_;VACmI5dr>ykwjKc%Z?X>196Azt1YO{ByXym-(ruh2(@l5mNoi6_CgMj3S&At zWzbtzL2f1fOd#hQ_ls1pBDc22xff(GJVt3oPlo2Sbt?}E*^W^Na8L(sGr^;0SRT0qX(Mbl z0?1JuA)|r+H?bm5+h#7|Pas*5S|Kt>3awTt_Hu0+=!v+#2kd$s>gY3!r0f9Ii&#Snt_L3bD@ z+&#K%dxW?c(kK&K_bnMiv7G77Wwx_b10+}xcyrdmQ+EIw9Um^+IBu8%qQDGG)v@r= zT_7x03VBnJkqHXXA*Gu?8;>B)=yMFI_?MU)qi2vo%2kF4EmRpiCYqBo&JL+?@kvfg z_0(w9C4yG;zi<4|)w9*j{qoKA43h70AbVrl`8|+wXZz&Yl|jInOgXVE`709@T2Bc+ zloj=uDd^N$vmz)-obzU4Jg5;e@ImMZ#pl>H6La3eXYESC1~M8Y9kx^Xl-@5%*$Tu6 zHhmq`ltIU2>tvxxRJmt$_&x{oNs#4vJsm&^T_>EulDSP4@KnCB#i^BL;Ck7V%l8In ztW+Om3K0nC0NGg}&{i+-kca4-4(D^wFe9;05}MHa9d}`fU#Diy{7vM6Tj@CDgB~I^ zugFlQ>iFCu#5zo7^RaBms=|L;?052r%%lX>y@fs}6AHGz14ra%qJ9d;8&##cYHR~- zokUCk7ViIoJC8Aq3>=0SV1~2FMAIthnV1LI@i_k2Fi+iEoHbGEDu}kyu$~FP(cmj{ z1q$)!$W_LXoJQ6ZYYxiVrg*KP!61`6kh~k8e}f<8!@}!0V!B9wnSU#=_v3IK0~M@ zQ;(|5AfA9X8pNutw0y60+8ML5(S$2iHYQCO zL~~LZaOwa}E}4oNB6|w4V9fjF{k!V|tiF1&T)n+pu714!`FeFjMif<92Ze4txJ@aVKuy-`(DeC*=c& zGQnkyrj7kXfLtqExt-4NadmhlAiW&mdWCoE+3hnV6cAg!N42cI!T8DSu@mA}G8&BRnF&tkqc>W*Cc6!ZoZDZE&=A*u zjX;`Ul=LO0lWtKGqNhnw76yJMj6IXC8J{uXIp4`Pb+k>TYG_w@1u*04%;;R&mXIir z>uAN4&ZD*Iw#-kC0h6IC$7Yp>sKx2rcysV%BOT~~7DzUYWPYDTV@4aJE*!wut1GOl z=U#)O-xs&H@W}F?uhE4xEdWG4_}3TmSNHHYQe_|SlHl+DGZz&8HHzspA<$|AS!1CM zAHr0lNS%DGRZ}?u1p<0Sg<47gYST zpOXd@r)N2CAj*)ja@$2Tvk%2MT&-?YdS!)fNP{L07tTOA8eAg=&#+cZZ$ACYFQ_I2 zo{snN-g4pIHI8S}kVD#Xhd0(74CylQ*8}|hCVnNoLC>RG*5BxHA0$=QGfl&%$X^H* z7x+MY=koG<6cPFn1OhH!etaHiyzYD(O3)Z1DpDMgx_+~vX_=gi>_Q;RA%y#jlHvVZP}(SC$I zI}rfr5X@to(hbdTT9C2sD%-c?ijd3C8j$NGgf|W7u31pmUu1X%UdjK;fTO#{)l1(F zb4b^N;nG(O-(hovzM9+7R^9X-bhu8~JTZW#Oe!>Jxi)*MIAC2Uxf2ObAU=ReIWSoq zl-Q&OQkf-OX`p$6uenhoE{(*8Gpcd(jQ9r455TVq#kB^hKx~UlAQ+-6nj67&1R`fy znTUK70RliS4P;^~42~HYc~bIu4dfcOT(J~?(pY4|9DH)DkE5#Q3XY* z3aL4uEs_Y$GAgz_Ss^n<=|15C`nO2c6zW#WS- znyZ~)T>pSf>X25cc?1bHG!P>MMulyx<5G(dn#c`Tsw|9<`2{-PV=Rg=imORTSLVSg zCM4CtgZd0Y_z~<=j_=9`8j_+u0*#3=b23Jd4+AtO9wFzOOl)}0xK|@R%3f%GfwvOc z4~SRVJw?tkSoSwURV0)r|JW#862uy4vJ+nRaTsr}#qoaVIiwFp;j%s57142_wEio=IE_8Tw0CkeVZtFG>Mfd!QK~{Z$66C!u3Unu1 zbWBth4T?^hB`whwTS+uXDyjSRossP{K~X>plA3$x&LJ1x#{{)Mq<0f6l&-O3v~Um4 zHbmz~`2O&SyL>uMSoi&x)MfDF@$qNIwl)kd&NVJVXM^3J;TX)AY@5L$SPT9DO=rT< zW{^CX@eC()MS&0a9nI+eHVF-w-zVcnHy*)2<4)AZLdej<~*+jMu|D8>{qPOzuo+o{22>*A?5=XsHW+fT`6%>HE? zTFi|T4iyKN=14cQ>n{%{^rDEZ4ekx&yjghn;m>%Tf&EuN;Kj3IrzT!?+E5s#x(8;VsOVU!RQmhh~UPr-g6jY zg%BO?BcilKG{e%SpIS6yq%eDg`$2TR;OwFdmVh<$4P5L#1tFYGZ`@!*#s+#kdwX@p zVK5C%fiY?L>uvu_3V$Pw-qJ(CH9?y3F%ta`=uh%#>}`z5sOdghgiktl(GiA-UHbEl z&cTO)>;}_xZnXE8XJGb}$i+9w&3O_#!+Kk3Kx$Wvn^W za;0B##X;1tRq|OBynwsB#{FFeFG8>7P6Jk`ywa~ASCCh)@SCWL4EXO`#p@cRVq&u` z1;;Z{Ez4aYswY^Wu96x`u@M?gwFGK-wGzB0vkh0vHE#2TD20B_*h=V%JXcad4%=L5 zvD}rpg6&RiWz93tLYEv<6zE>vi)y8?8{hCsKVWw}1pbU0Rn3W=b0kYs2JztcZtuEzI143+dWlv#iEio=IE-)@_WB|QXO^?(t487-9SlR=ys%92( zLkMX>dsqpU6>=rMFQW&|b} zDV$)m+$v7Fk!l`w$k75BZRxOpv9%7N55#EL`UVVn4z?VaLR592PKxT%I?K}`GrBbf zd)D3vse2C;Dh#PyK!ZXH_=0Ew6Ai*GGUz5CrZ~${g~4Gw06et_`3+R>5+M;SiCdu3 z*+#SU6xHB!tyV8^9eR2BDv_>ij!6}yW>|p^>gUS96GKH3KS?F&G)V({X)?65-!w7^ zr8Bqr&(w#}K4DOhROd2YP0rCc3-g)!Nm5%@>Q2ivE|gr^#Ec^pg-4#=3npsMWTe4W zASz%Ot%zcM9VCAFdV&8cDzjFXDA9PP^gt|yqxvg?uozbO%|ByH&>%<9kYHpON>qYg z2i^v=G0UEiHj0^cR)bp_SeaG}xmbX9aRC(S!1&Dn%vaL1{O~7HLw#tO`}qENEM+f9 zp9~G&Sa+b%9G8S+UWt!$TX)Z9NIP*~r)j1RWEQrzi@qYj7;JX)HoI1zbCl@R_0D27 zv;Vay^!xRdpI>i^b=Gh~?6aBF%DS9@^(g^sF+d-*?2OS4B4eMem(iz;EiB&Ms7g;F zYt7lWGf#u!e4(Dohz}N9Mk;p3Rp_e-w(GF6n$a!W_b6}w9~?H%Kh*-`wC$oC5uCCt z7b7fD8kXSF<<;JHE;0R%+u=~^fp%mQOu#dp_UB?XtsKNH^ZNSwHbSjKx?4#?r^lo| zjbgODGZUAX!fY(mV#?fzd=1+3lqhefqR5xS?}(|q*d^whH}|v{tWJg%s7iNQJTB~= os8gkgy{r^oT)_EgrCc#il@`HaBc92!9;7|>2kq>>hY$t;08`IvGynhq diff --git a/kuksa_databroker/createbom/licensestore/CC0-1.0.txt.gz b/kuksa_databroker/createbom/licensestore/CC0-1.0.txt.gz deleted file mode 100644 index 579708c83cc882847ea9afed890828ae8be1739e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2838 zcmV+x3+eP9iwFoik85K914BbFEio=IE_8Tw0Hs;mZrex_edkv+{IWK{D3jg60NFe# zvYZHGOMxUOn8y~`vN|EzoNiKz{(eqXH7P2#bJ-mXVDVP>I(4cu@kTdxZ`8zVk-APEEgYV*He~rJAF64RjcXp<7_frjnwsQwO-EN-m{#= zjat8luj&ZmF9nB30jwdM4d4OzXPeHcA9HR@lna27C| z-z=7QVm$sI&(+0v^gt<>#o{C0LbTmPjXLS2vV z#_wRva=N;|U6bmY<>HP-{Vz83`dLD6!zf8sjc!b7sz$l3`q28?1r*47XH=mNfo_&A zH0pEfZOCobSgNIF=Uw}-b8Um4Mjf0la;4kGm8iK)7sXL!uG$)(n6FvU2C2jP=KwX0ZkMrG`LLf?dT6U^T&+j^*szYJIE(&%i* z5}`H44|T!MF0ROQTsr8q6)GP_e!;y2X6~F1J6qFdFP&Ff<+{-u9gK*B7(shp|b>EHv7!&Db5p?IN}}{B3qx(owgY0&isSo-ETF zm`D*i*oITKHQFaoLK*NXE3_?Hsjapi#z-}6T8o@g9#T|5Znwu2FJun(dwi!TB2eZN zHYA0n7JiW$Z*m*NHQWel>y04`f`aS8ZVLWbS4WCUsSYqZI0GEwByTApcoriSSZmSd z6s69A!j=|gi&Es68J}4MsQY3>)k`s!gq8YuinXCgQ;a%Pq)d8OI(mZJHaCz&mBVHy z5`FQDo^M-EPSZDe%gyk7w$v$GU69}#6h2Tnc~iI12i$!i36R@Ij_y+^pv`)zAzLN2 z_D$D(Y)=<+v&G8|XOXjlAS5^Pxx7Jj?!@#MCjJhN+dW$m(z6;t3edZ?$vPVml03Kc z8{Q$F0ip7}{YXP?s=(K&6d{aoRiZ<1$PO1dO&yZoHN_>pcQM{>tuLu#(=IvYYeOZ- z1&vF{4?C0C!2L{FC3C)uCsxpd)TCGhJ1(&&m}Mc1}M7;?N{@aRU4 zVLQ7HqZuDhSc81O8huyY2&0=-l{!aB?6oa4^`baLBB@h0CP8gCP()x%oimi^qeOUD z8Qk4C0*nss2#f}AC+GSBrauY?^*NeoL-mKIt6Yd&j(X0#s_2fGZkKJ zlN0!I1p|`wgV*&={eG#@!aTrXfqK${*xg=df)vO^FeL&fm!}cZ%8;bNELIG?+arek z$nJ_Sv_u3#>P~y;dG-4BA1YE5?oN@^c`AU}nHZr}OrhB(?xI+1SrQnUzcH!P5+x$1fu9Q5m@}0`kt;t2f++dn!4>{(#&S+NTOM3Po2im7+rM-UN*L ze9+D398W|G(IcO7@}3|ReM2Y$vdGho=GamE9eNsbc;;^CTm^Rhd!#;T+C@fcEoCMX z5ycvZ0r4%{2r3Cg03N6+c(&_3OYxX-EyXl1=+A)4rHMr- z_Acv56LL>+5jSw}KxR@#H+b5Q&CudA%5NYZN;I=mipKpe>T#svki^}{#^`RQ(FB2r zTGuUyo#8ZM*zm;R(c4z?^YTF_xw zows1&7UpmX94z7VrNt|eq+ob_wPjnXyp5~?y|A~rAmpP$Nu*GQMn?l1TSfvvl^w2F zO*91sm2sfCYUP8Z1l@$*A$P3Waw8-Gy)3AvG?rqS0IVX42EAYtZ*eFQha^R49pPg@8a>%16{dN3k1@Iz#z(ki*Zi0f9k zLERB`46-+Lh!JAZM{XgI44Dj`(VnoQoKtsg%mDlo=?keuz(oe==HJ*eG89?I{ishn zJdeQ^@DUb++!OdTTntipN*tkgP3M z2*g3|1WpER5&f1UMVPBoU+B;^SWc{)_e6{=4&ZrL z4|la^yR=gn-A<%U)&JS1Ot44|oi)TSiNc?M%#{3upz%E&H%Mwju*A?xXOzrZX+Tmv+`%mO{^eh4m*9?!f1IIf8o{T3%J$G44hK~}p8O(l% z_k0+fHiQ>89>g#!sAPo&?Drfw?t2IA31e*}Y{&%=Kc@g@##h~HB|(niOPO!m-VI1> zfoI1v(|>ThcBYoaU|%G3CRo_viQd@465|JR;o9e><94)J3#!tA0|R;@o80M`QI5o5 zx!%C%jCa05GSweg<%WVwc$NVOu_>orP?!lww3up~WB|LF>~xHo4lK|lU>O;)f0;0h z@~)TkI@+;T3^Cy#NlJ3aW>F_-XZwb$)pd>l)$&DZ+L21-!)hR=|54!oUjH!)Hhrpm+I<*92$pf%F%@_|pwu zmtjhNEMQ*ZM;QG`X+xr$hv5`IJj>-vc)cW;Vj{@ge{Y40xcYcYnZ_U zH>B5Op|IazRm#2+>ae*)+etwcf84r;7ERgE$oE1D_snu}Eu2DYcN73h13sa0V4EEB zhiQ)>1>Z}AnkKHE!FE^*E(^jnSh|7<_5B2-D7CWq*i#m1pyDk*WQ4o*XFN9CSxt=w z4BB40OkW$_GO6tb+*_mq?s&G+-U!wfL;nV8d6I-yloQ>imN6DT}LaX?if8JXVH zP8$;T_S;YZH^Syd-Mj48TOeg9yeH;$Z#y809MhqppKtk=TK~WP-4|V-Q(?sd004Qd B*Bk%< diff --git a/kuksa_databroker/createbom/licensestore/MIT.txt.gz b/kuksa_databroker/createbom/licensestore/MIT.txt.gz deleted file mode 100644 index 37744a6241720397968b18f574da303151dd507f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmV;60(AW!iwFpUjcQ{615HU(09{gFZ<{a>fA^<2<*AiW_r5m=oW>epWJtTH>H`52 zJP{mWvnbzwcO+fcNs*B6?)UF5nXDkSjTyaREOzJXWRHD-hvpI9uBM*e;jNp8VXRN) zow349C+od+BUlf;natq|$EhBJX(Q++W59LL^!0Q!5d;VIc!jf>JObPy)ONJv5o%~q zh~Z@Dk;c0&TR*#EFYwCg75vcdk zf{P8kn*&V7hsid?5rG|>VQ$I8M|-d*dsiU%lHM~UojoQXpAno~YdiXyCDwU94A%D% zw3et3bHJjf;p=@>IF>?({W@^{ktx5hcxn zX&tU?QT%0^KouJA+%UKcMQhyHT1w=TftVPiNNAopfkQs#Z3xB#VMCr1PRahvsh3H zSu~@un>%>j3M!Ev$6s7Yl~asZ<(0-~gei6P7y2qo5dqh-q=js>$|6SVM1)#M5SNP^ l3#}TyTm(nxy(`6ELP!Kpk*g#yMf@0k`U7}2iMcEU005g;K7{}P diff --git a/kuksa_databroker/createbom/licensestore/Unicode-DFS-2016.txt.gz b/kuksa_databroker/createbom/licensestore/Unicode-DFS-2016.txt.gz deleted file mode 100644 index 7a0140108eafec0c08087b4da0a943da8384fdad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1219 zcmV;!1U&m6iwFqnk!oWA166KmV{c?-Eks6BEiy1MHZF8{bO4oAQEuZl5dGIF2Ki|g z&^q1x?V>0kOLRQBX@EdsJ+Nb2^J} z8_Ih_KUKr9@4wvL9goM!p|R_>G?TX5-mTmHOJ}#$FsX)J{j;}eJ1Wh_Hg>RWGschG zNjB@rKY#q$Q&bEE&1`LYDw>jXyBUr}XC|JPs0?LNrYP4U{X!u=Zw__+LY*l}8Y)AZ zwyxWwZMIaKZBbLP?Tp!(W|(->6-DYPiB%BEHf+p-Li|NtNhvP3qUKO*}ax&J-yETjPR%emfuka`y4y zSeH6W)Wg|=PM0NTYiOak7uuVyM?m{L6cB2&^$KEO-pR$B1zWOCHy539 zWYPES+7?`V*{%<)yMl%8-E!c~tFmuC5GLV_)So2&y*THQ018Sj4Rj7tc5wfliC6CH^xwbnyCURh><{-tPH@?Rl__S+FyW#)FQMNxk*S4>G zDld)m`51Rd-y3uoQI@OOc<WP+&| zzb#Xt-89R^GM2(QK^W(3h=lQXE)mOx%m4~AV&geMN#X2fA<}S;*I+7RnZY_{GD{e9 z2GD?(K?(=R;~=GFo-P&NC`kn4PGmAmk!8GFM&C*!w|_;>OEkQT9fZUqZ_#r$KW5<7 zZRRSDM9SrlPx@3nibW_p;rWVyi^ejT#$v1s41{qY7e1Zd^iqT}h!GaaRD>CShp%eb zGm>KkKEDVaguXcO1Bz#?#{?k0KP*2V8@vxi_=y$yRG#>e>z^gPPeclvLNowLp2O665s!>ql&;&H)d zdN%AD4xlK%nr^T?TMY)L~h|Qu>Rz4{d>cAv9Nt- hF^0#^4ue7F1HN|l+vsVh@qJtLiwFqrjcQ{6166KpX=7z>b7d}ccys`5R9%moI23*7S6ua(&b+Uxl{|^l zSS1h{((F7sU?$#zNo~_A`|I~ylFoEiDQgm$9<`f=bYwf zbG#cbZoosd!;sSyvd+a6+-Xk0vZr6tIavq20A=jWp|t>amij4-z>$e$e$jQ=$$1l? z*7F;Gg=)A=cfrwy)|r7pe)1pRcJih1)0Gj~XpN8PM|t{t4lZ`CO>XiLu1rD>?eyZ^ zKX&OZxR-OH!TgN*l8Kqq8SJdRJjHD4-*-cu1))iHamTV|7=GhIya+z>12bl?xc^O^ zj+RFA?Vi}38fKUFx%_0k?OnRrctsob9A0kceJAcL(jTo)gj&Q*XX`@biY(4;Yhy$^ ziy&KM+m6f>r3mWE^?53a7%;Uyk z#G5x4-%^-;he>!BJ&vl`N~)_(a}-*Vs%fvQuWBvV^g+~Ef5_>mnr(Gx2o+kC%`;US z66G^}QRO<%zXP}YPTrb_IQ{E7wD zTTv8?lsLe>uIWj_gm^0CjTQb^g;2Yk)?z0 diff --git a/kuksa_databroker/createbom/licensestore/WTFPL.txt.gz b/kuksa_databroker/createbom/licensestore/WTFPL.txt.gz deleted file mode 100644 index 9e57dae5fdd3e640c372b3833ff48e29c67b0d4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314 zcmV-A0mc3wiwFq3k85K916Nc=P)sg#cys`jP|-@mFcf|7SDZ(MQHJ;^V%K&q=$f&% zjy-10T^m`Fk*1UVy=i?AK?E;c$UQmtoXY{eE92O$k_y!-$Ffdeu;(>)Nf8i^O}%(! zDMIH(nMe4g-pKXJ8r;p0QA7Gb4tMkUeH0U5Qrj5pj?+8Zd>6D31GLC*k@XzR~ ze7i1@6d6)pWUOMmD6!<*FmCp&cn$%wvf8pmJ$_BZHP6_RrO614-t!oHJK%lj{h#jf MC*s~{ZsGv|00Lf_UH||9 diff --git a/kuksa_databroker/createbom/licensestore/Zlib.txt.gz b/kuksa_databroker/createbom/licensestore/Zlib.txt.gz deleted file mode 100644 index f9c19c9ecfda58795346ed73132288aada6df1e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 488 zcmVl;3425_73T{b(tAVszI~AP*WayAB z$RNwK%|;SkN;=p5^(F1=AwjyyC-U*VkGemRdU&9KxuA2m-#@_9hF+fGX>2iOpYYka z$C(Ng9_#7_LC=funFbu-#+Q#&ZceaLow-%;c?0~t2$ljYKxv7DgVRRwxo#c6eTK|{ zXUtW*VuU&)_@?brphuW74iL%r5n)sbQyhHq6Bg%%3grn#;k5U)g21C5Um5J2`+<_E z6yj`dCmXG1E1MW+w3BtdX}b|Y+M^NwKLYpJ$RC#UAE5)bf1m{u epH;!0$i?3N2JO9Ed|sEXX1l*c5T5y00{{S^c=2ce diff --git a/kuksa_databroker/createbom/licensestore/ring.LICENSE.txt.gz b/kuksa_databroker/createbom/licensestore/ring.LICENSE.txt.gz deleted file mode 100644 index 651640e65488a31ffb59549a77292d17d2ca088e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3341 zcmV+o4f66IiwFpmMC)S!19E9@XD&=hLq$$gMJ{xBbO6m-ZFAek5&n)}aicGmI1m-P zd2y8KOdt}H&{Bj7fOa&UP6L8R5-|v{coD;Y-)HykK#-y>+f^sgIFSV6_ICGnpL?D= zjf+}}dKuRu#lK3(xY~+&QQ{eXo2MB*EyP0BqG<5nTvXdU5u3DL;teUXG?95FE0N~( zyHyoUnMjcoGs%OizVPZ-l_+IWtX49g$r;(hFYCCJ$4rQh35)01z&n`0=sGQO7+A_u z_ARSdrum{rPS0eSKH`IUS**lWLC?c*WW!Wv20Rp1S~oFSp~>3uR+X;OEH25jcJyw7 zhMbFY;e~_qs@`U;%lQ65?nZFhIC2=zPmnJ$*Kc=OHc@6PeR@5NP_!hvvwboBY9ds(j1s-j5XG(5CnVZF7*s+gs7 ze2??l1>BjXRb8gjh8G!`s)~8Nq0E!7alR#6>!w^6h=!Am$Ml^RdoCp0jMiIqv9r$-*sH(LeQ`~ls0x;fpWr8xwam8Mr_1;e^(bzNVv)&C5mWW5 zzSp*7Uqn>RrvFm{HuS@+Nzf0v8>U5F1BT#M3!w;YP~@r+i?Z6o8Fr|Y|7p@vVdK2W zvSP!gP}QPr$aQMh!4mM6Hmgf(S=a08^5P=N;{HrN%B( zyW&7C6iu!6741M@gg{F6&{DaV$Kwj4UY$(`F&^W;I2TVVzMILjJyn3rKzk*lG6#0azjW20IAeP1VL<(h5>$ z8Wn)5y$!ni5_s|Ehc|D3c>Uv#=Et{hzuEox7updH770(z_rEObq9^|P0$-Nsb@t!W z2#TCr=44v6xfumWZ4(mnKw_J!K9tU7-uxn{-6B8 zq}mF-F)NaW7-wwOj@Xn!wG~Uj- zsC8||w6QJ=^HOA>@Rar@Y)zZZrr&{?i?b7*hi}!6lE*8|esVDWgjeX~VCoYUEfyCj zOS2QuX@4LofHVZy6x)i_jE?a@7VOjCPJmi{lDaDIKpKd{(dYIdx+*gt$5<8m zcYTWJS>IMzQ5|c7-9qjXa?+N0$#1pKJ8W8kt4gn7@_X@_n0LUfAo&TnX|KOOiWRg8 zac`13s|plP`2;iClGIcFfra^eT^>k-j_kO4U<%t#8~A?%y%oRy%5vn@D;5OI?R&!g zrisYRQ7!T*A)@q!xOc$O2a}N#kd^yM zaPNb7Q$R)|xkGGP$3@FwfIb_6Xi&nygTF^L%@G}gD3LmNIVJH~fjlKT$+>M-u%+KVMBC zWhjr{IC6tva!>N*jK<#j?^$FGoCz%}<=h{0*vOe5Jdj<=2QSHqF?tYBN=MdtEPts4p6=lu-J09wN==*I|mS;hbxXt{+`Hny`%ZdA|tg611Rig zs#@%eno_Q?KUbYPc~#l!s6(Bu@YX&!ILWItJ60+hd8K8cgdo>bI=@&Ix^9K14?a3| z%an~y`b@Lh-7>AfQ8JSFVgX8ox9T=Uyrz{R{H!SrS80!a)cLNeKbofBR%L>2nYMg@ z3z>KeYjM)%AV?MY7ZX1sC|c1;LRmL!kV&qZNskBdm?SN|79qBOK!wDw5-Jg!R&aA~C#`55D!Lxwo$} zS2EX{V%y%6^cQ;I^b2FZZd-hz3jzsqVr9_E^=4cQ7867pr z?%rdWyXW?9>GDvTBxii7Y@53-FHeltc)1(p-izHR_g>&e*_`ft(VcP&M&Xk?<=zY2 zDfhnqPWjlCa_>d1lzT6HrQCb5E9Kr-Un#5JiHvADxCy0;OZ0L{*Nt3uz;n}Nmvm)& z*f;8rF_?T|=(!>$?QPd-C1raxyFke|Q@)D@OFv&{j~AUW7t^emUaaB@sCA+LSO9d! z>NMezK4Ec9w023?-!|)9!aBejq1u#)I`ctp8|#orYLQnJkl@6i_K7b4u?k2Bf;$QI zh?6s(WG3Ux(i$KI5q?I*q${bUw8`N2Wl<|yoylgIe zk4dUaRa*y&L-ms zOb@8>{|=0>J7mz(VAWxON2m_B-X}?)Z9T{M812UX*c)F5n1xx>M^Mi)e@VkIcK;A~ zH@6WO&}ir$J&I<~w!0X|NMjx6LoHhELlu*tF5TGy6QQAPb>ZnKHnl54lxl}n3iXDr XGlDH*b{yjF4`BWa+LesVjVAyAc}s|4 diff --git a/kuksa_databroker/createbom/licensestore/webpki.LICENSE.txt.gz b/kuksa_databroker/createbom/licensestore/webpki.LICENSE.txt.gz deleted file mode 100644 index 5da686a854fa35ab341cf1ec1e8a6975d607f185..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 595 zcmV-Z0<8TXiwFqb9Ux=?19xR&aBFEUOi4pUPE$oLba-?CZBtEe+aMUe^DAEUv`KEe zP1OpdXDG|Ru=i_?!y+R0!)pRa-a?(CGHjo{P4hO>(nMxSh7 zKsvYxQ}DlRmjIW8>+Be952vxW0Y6*V`(f~BH$Ib3T$i^oT?YFZk`2fBgOJism*Acc z3BG;#`W+U*wIk@GONTo`wg_@DIzK}4aEi8o4)FyXeed@8Y{&lI2k2c)!9AUly#|VY zpU!Q_-T^TeGM&QYG4&aB0pI1PKPA{(n^R*c`*eZl(2jE}EcD`fY>^IanoG1#{>75+ zJuKG8rrG~>1RqJ?K24Kt1Go{|VaTzajabQ4476OC9aRjthOLqhe94w@LpAPifQlt# z5N%8)m4+n_t)_efw5|bJiVDM-COd8_P;5;V;w4g0>_b?Tb+hDRJ+t^`TXVGdV1rzd z4O3->Te{#iH;=RNiW|YSzC!^J64(P126UB0{?4>uP;|Q>H>BZ!)z)?rh?GYa49kxO^u>Cfne*JubC)WCdwIYq(We$;YuigDz3AmY)qbx zoCQ%su&d%c?>q!dG5a%x=G h3|_C^#tzRhZrn)z$GER~$#9l;) -> fmt::Result { - f.write_str("parse error") - } -} - -#[derive(Debug, Parser, Clone)] -#[clap(author, version, about, long_about = None)] -pub struct Cli { - /// Server to connect to - #[clap(long, display_order = 1, default_value = "http://127.0.0.1:55555")] - server: String, - - // #[clap(short, long)] - // port: Option, - /// File containing access token - #[clap(long, value_name = "FILE", display_order = 2)] - token_file: Option, - - /// CA certificate used to verify server certificate - #[cfg(feature = "tls")] - #[clap(long, value_name = "CERT", display_order = 3)] - ca_cert: Option, - - #[arg(value_enum)] - #[clap(long, short = 'p', value_enum, default_value = "sdv-databroker-v1")] - protocol: CliAPI, - - // Sub command - #[clap(subcommand)] - command: Option, -} - -impl Cli { - pub fn get_ca_cert(&mut self) -> Option { - self.ca_cert.clone() - } - - pub fn get_token_file(&mut self) -> Option { - self.token_file.clone() - } - - pub fn get_command(&mut self) -> Option { - self.command.clone() - } - - pub fn get_server(&mut self) -> String { - self.server.clone() - } - - pub fn get_protocol(&mut self) -> CliAPI { - self.protocol - } -} - -#[derive(Debug, Subcommand, Clone)] -pub enum Commands { - /// Get one or more datapoint(s) - Get { - #[clap(value_name = "PATH")] - paths: Vec, - }, - // Subscribe, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum CliAPI { - KuksaValV1 = 1, - SdvDatabrokerV1 = 2, -} - -pub fn set_connected_prompt(interface: &Arc>, text: String) { - let _text = text; - let connected_prompt = format!( - "\x01{prefix}\x02{text}\x01{suffix}\x02 > ", - prefix = Color::Green.prefix(), - text = _text, - suffix = Color::Green.suffix() - ); - interface.set_prompt(&connected_prompt).unwrap(); -} - -pub fn set_disconnected_prompt(interface: &Arc>) { - let disconnected_prompt = format!( - "\x01{prefix}\x02{text}\x01{suffix}\x02 > ", - prefix = Color::Red.prefix(), - text = "not connected", - suffix = Color::Red.suffix() - ); - interface.set_prompt(&disconnected_prompt).unwrap(); -} - -pub fn print_logo(version: impl fmt::Display) { - let mut output = io::stderr().lock(); - writeln!(output).unwrap(); - writeln!( - output, - " {}{}", - Color::Fixed(23).paint("⠀⠀⠀⢀⣤⣶⣾⣿"), - Color::White.dimmed().paint("⢸⣿⣿⣷⣶⣤⡀") - ) - .unwrap(); - writeln!( - output, - " {}{}", - Color::Fixed(23).paint("⠀⠀⣴⣿⡿⠋⣿⣿"), - Color::White.dimmed().paint("⠀⠀⠀⠈⠙⢿⣿⣦⠀") - ) - .unwrap(); - writeln!( - output, - " {}{}", - Color::Fixed(23).paint("⠀⣾⣿⠋⠀⠀⣿⣿"), - Color::White.dimmed().paint("⠀⠀⣶⣿⠀⠀⠙⣿⣷ ") - ) - .unwrap(); - writeln!( - output, - " {}{}", - Color::Fixed(23).paint("⣸⣿⠇⠀⠀⠀⣿⣿"), - Color::White - .dimmed() - .paint("⠠⣾⡿⠃⠀⠀⠀⠸⣿⣇⠀⠀⣶⠀⣠⡶⠂⠀⣶⠀⠀⢰⡆⠀⢰⡆⢀⣴⠖⠀⢠⡶⠶⠶⡦⠀⠀⠀⣰⣶⡀") - ) - .unwrap(); - writeln!( - output, - " {}{}", - Color::Fixed(23).paint("⣿⣿⠀⠀⠀⠀⠿⢿⣷⣦⡀"), - Color::White - .dimmed() - .paint("⠀⠀⠀⠀⠀⣿⣿⠀⠀⣿⢾⣏⠀⠀⠀⣿⠀⠀⢸⡇⠀⢸⡷⣿⡁⠀⠀⠘⠷⠶⠶⣦⠀⠀⢠⡟⠘⣷") - ) - .unwrap(); - writeln!( - output, - " {}{}{}{}", - Color::Fixed(23).paint("⢹⣿⡆⠀⠀⠀"), - Color::White.dimmed().paint("⣿⣶"), - Color::Fixed(23).paint("⠈⢻⣿⡆"), - Color::White - .dimmed() - .paint("⠀⠀⠀⢰⣿⡏⠀⠀⠿⠀⠙⠷⠄⠀⠙⠷⠶⠟⠁⠀⠸⠇⠈⠻⠦⠀⠐⠷⠶⠶⠟⠀⠠⠿⠁⠀⠹⠧") - ) - .unwrap(); - writeln!( - output, - " {}{}{}{}", - Color::Fixed(23).paint("⠀⢿⣿⣄⠀⠀"), - Color::White.dimmed().paint("⣿⣿"), - Color::Fixed(23).paint("⠀⠀⠿⣿"), - Color::White.dimmed().paint("⠀⠀⣠⣿⡿"), - ) - .unwrap(); - writeln!( - output, - " {}{} {}", - Color::Fixed(23).paint("⠀⠀⠻⣿⣷⡄"), - Color::White.dimmed().paint("⣿⣿⠀⠀⠀⢀⣠⣾⣿⠟"), - Color::White - .dimmed() - .paint(format!("{:<30}", "databroker-cli")), - ) - .unwrap(); - writeln!( - output, - " {}{} {}", - Color::Fixed(23).paint("⠀⠀⠀⠈⠛⠇"), - Color::White.dimmed().paint("⢿⣿⣿⣿⣿⡿⠿⠛⠁"), - Color::White.dimmed().paint(format!("{version:<30}")), - ) - .unwrap(); - writeln!(output).unwrap(); -} - -pub fn print_resp_err(operation: impl AsRef, err: &tonic::Status) -> io::Result<()> { - let mut output = io::stderr().lock(); - output.write_fmt(format_args!( - "{} {} {}", - Color::White - .dimmed() - .paint(format!("[{}]", operation.as_ref())), - Color::White - .on(Color::Red) - .paint(format!(" {} ", code_to_text(&err.code()))), - err.message(), - ))?; - output.write_all(b"\n")?; - output.flush() -} - -pub fn print_resp_err_fmt(operation: impl AsRef, fmt: fmt::Arguments<'_>) -> io::Result<()> { - let mut stderr = io::stderr().lock(); - let mut stdout = io::stdout().lock(); - write_resp_ok(&mut stderr, operation)?; - stdout.write_fmt(fmt)?; - stdout.write_all(b"\n")?; - stdout.flush() -} - -#[allow(dead_code)] -pub fn print_resp_ok_fmt(operation: impl AsRef, fmt: fmt::Arguments<'_>) -> io::Result<()> { - let mut stderr = io::stderr().lock(); - let mut stdout = io::stdout().lock(); - write_resp_ok(&mut stderr, operation)?; - stdout.write_fmt(fmt)?; - stdout.write_all(b"\n")?; - stdout.flush() -} - -pub fn print_resp_ok(operation: impl AsRef) -> io::Result<()> { - let mut output = io::stderr().lock(); - write_resp_ok(&mut output, operation)?; - output.write_all(b"\n")?; - output.flush() -} - -pub fn write_resp_ok(output: &mut impl Write, operation: impl AsRef) -> io::Result<()> { - output.write_fmt(format_args!( - "{} {} ", - Color::White - .dimmed() - .paint(format!("[{}]", operation.as_ref())), - Color::Black.on(Color::Green).paint(" OK "), - )) -} - -pub fn print_info(info: impl AsRef) -> io::Result<()> { - let mut output = io::stderr().lock(); - output.write_fmt(format_args!( - "{}\n", - Color::White.dimmed().paint(info.as_ref()), - ))?; - output.flush() -} - -pub fn print_error(operation: impl AsRef, msg: impl AsRef) -> io::Result<()> { - let mut output = io::stderr().lock(); - output.write_fmt(format_args!( - "{} {} {}\n", - Color::White - .dimmed() - .paint(format!("[{}]", operation.as_ref())), - Color::White.on(Color::Red).paint(" Error "), - msg.as_ref(), - ))?; - output.flush() -} - -pub fn split_first_word(s: &str) -> (&str, &str) { - let s = s.trim(); - - match s.find(|ch: char| ch.is_whitespace()) { - Some(pos) => (&s[..pos], s[pos..].trim_start()), - None => (s, ""), - } -} - -pub fn code_to_text(code: &tonic::Code) -> &str { - match code { - tonic::Code::Ok => "Ok", - tonic::Code::Cancelled => "Cancelled", - tonic::Code::Unknown => "Unknown", - tonic::Code::InvalidArgument => "InvalidArgument", - tonic::Code::DeadlineExceeded => "DeadlineExceeded", - tonic::Code::NotFound => "NotFound", - tonic::Code::AlreadyExists => "AlreadyExists", - tonic::Code::PermissionDenied => "PermissionDenied", - tonic::Code::ResourceExhausted => "ResourceExhausted", - tonic::Code::FailedPrecondition => "FailedPrecondition", - tonic::Code::Aborted => "Aborted", - tonic::Code::OutOfRange => "OutOfRange", - tonic::Code::Unimplemented => "Unimplemented", - tonic::Code::Internal => "Internal", - tonic::Code::Unavailable => "Unavailable", - tonic::Code::DataLoss => "DataLoss", - tonic::Code::Unauthenticated => "Unauthenticated", - } -} - -pub fn get_array_from_input(values: String) -> Result, ParseError> { - let raw_input = values - .strip_prefix('[') - .and_then(|s| s.strip_suffix(']')) - .ok_or(ParseError {})?; - - let pattern = r#"(?:\\.|[^",])*"(?:\\.|[^"])*"|[^",]+"#; - - let regex = regex::Regex::new(pattern).unwrap(); - let inputs = regex.captures_iter(raw_input); - - let mut array: Vec = vec![]; - for part in inputs { - match part[0] - .trim() - .replace('\"', "") - .replace('\\', "\"") - .parse::() - { - Ok(value) => array.push(value), - Err(_) => return Err(ParseError {}), - } - } - Ok(array) -} - -pub struct EnterFunction; - -impl Function for EnterFunction { - fn execute(&self, prompter: &mut Prompter, count: i32, _ch: char) -> io::Result<()> { - if prompter - .buffer() - .trim() - // .to_lowercase() - .starts_with("subscribe") - { - if prompter.buffer().ends_with('\n') { - let len = prompter.buffer().len(); - prompter.delete_range(len - 1..len)?; - prompter.accept_input() - } else if count > 0 { - // Start multiline - prompter.insert_str("\n") - } else { - Ok(()) - } - } else { - prompter.accept_input() - } - } -} - -pub fn to_uri(uri: impl AsRef) -> Result { - let uri = uri - .as_ref() - .parse::() - .map_err(|err| format!("{err}"))?; - let mut parts = uri.into_parts(); - - if parts.scheme.is_none() { - parts.scheme = Some("http".parse().expect("http should be valid scheme")); - } - - match &parts.authority { - Some(_authority) => { - // match (authority.port_u16(), port) { - // (Some(uri_port), Some(port)) => { - // if uri_port != port { - // parts.authority = format!("{}:{}", authority.host(), port) - // .parse::() - // .map_err(|err| format!("{}", err)) - // .ok(); - // } - // } - // (_, _) => {} - // } - } - None => return Err("No server uri specified".to_owned()), - } - parts.path_and_query = Some("".parse().expect("uri path should be empty string")); - tonic::transport::Uri::from_parts(parts).map_err(|err| format!("{err}")) -} diff --git a/kuksa_databroker/databroker-cli/src/kuksa_cli.rs b/kuksa_databroker/databroker-cli/src/kuksa_cli.rs deleted file mode 100644 index a3987f06e..000000000 --- a/kuksa_databroker/databroker-cli/src/kuksa_cli.rs +++ /dev/null @@ -1,1299 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::kuksa::val as proto; -use kuksa::*; - -use prost_types::Timestamp; -use tokio_stream::StreamExt; - -use std::collections::HashMap; -use std::fmt; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; - -use ansi_term::Color; - -use crate::cli::ParseError; -use crate::cli::{self, Cli}; -use linefeed::complete::{Completer, Completion, Suffix}; -use linefeed::terminal::Terminal; -use linefeed::{Command, Interface, Prompter, ReadResult}; - -const VERSION: &str = "kuksa.val.v1"; -const TIMEOUT: Duration = Duration::from_millis(500); - -const CLI_COMMANDS: &[(&str, &str, &str)] = &[ - ("connect", "[URI]", "Connect to server"), - ("get", " [[PATH] ...]", "Get signal value(s)"), - ("set", " ", "Set actuator signal"), - ( - "subscribe", - "", - "Subscribe to signals with QUERY, if you use kuksa feature comma separated list", - ), - ("feed", " ", "Publish signal value"), - ( - "metadata", - "[PATTERN]", - "Fetch metadata. Provide PATTERN to list metadata of signals matching pattern.", - ), - ("token", "", "Use TOKEN as access token"), - ( - "token-file", - "", - "Use content of FILE as access token", - ), - ("help", "", "You're looking at it."), - ("quit", "", "Quit"), -]; - -fn print_usage(command: impl AsRef) { - for (cmd, usage, _) in CLI_COMMANDS { - if *cmd == command.as_ref() { - println!("Usage: {cmd} {usage}"); - } - } -} - -pub async fn kuksa_main(_cli: Cli) -> Result<(), Box> { - println!("Using {VERSION}"); - - let mut subscription_nbr = 1; - - let completer = CliCompleter::new(); - let interface = Arc::new(Interface::new("client")?); - interface.set_completer(Arc::new(completer)); - - interface.define_function("enter-function", Arc::new(cli::EnterFunction)); - interface.bind_sequence("\r", Command::from_str("enter-function")); - interface.bind_sequence("\n", Command::from_str("enter-function")); - - cli::set_disconnected_prompt(&interface); - - let mut cli = _cli; - let mut client = KuksaClient::new(kuksa_common::to_uri(cli.get_server())?); - - if let Some(token_filename) = cli.get_token_file() { - let token = std::fs::read_to_string(token_filename)?; - client.basic_client.set_access_token(token)?; - } - - #[cfg(feature = "tls")] - if let Some(ca_cert_filename) = cli.get_ca_cert() { - let pem = std::fs::read(ca_cert_filename)?; - let ca_cert = tonic::transport::Certificate::from_pem(pem); - - let tls_config = tonic::transport::ClientTlsConfig::new().ca_certificate(ca_cert); - - client.basic_client.set_tls_config(tls_config); - } - - let mut connection_state_subscription = client.basic_client.subscribe_to_connection_state(); - let interface_ref = interface.clone(); - - tokio::spawn(async move { - while let Some(state) = connection_state_subscription.next().await { - match state { - Ok(state) => match state { - kuksa_common::ConnectionState::Connected => { - cli::set_connected_prompt(&interface_ref, VERSION.to_string()); - } - kuksa_common::ConnectionState::Disconnected => { - cli::set_disconnected_prompt(&interface_ref); - } - }, - Err(err) => { - cli::print_error( - "connection", - format!("Connection state subscription failed: {err}"), - ) - .unwrap_or_default(); - } - } - } - }); - - match cli.get_command() { - Some(cli::Commands::Get { paths }) => { - match client.get_current_values(paths).await { - Ok(data_entries) => { - for entry in data_entries { - if let Some(val) = entry.value { - println!("{}: {}", entry.path, DisplayDatapoint(val),); - } else { - println!("{}: NotAvailable", entry.path); - } - } - } - Err(err) => { - eprintln!("{err}"); - } - } - return Ok(()); - } - None => { - // No subcommand => run interactive client - let version = match option_env!("CARGO_PKG_VERSION") { - Some(version) => format!("v{version}"), - None => String::new(), - }; - cli::print_logo(version); - - match client.basic_client.try_connect().await { - Ok(()) => { - cli::print_info(format!( - "Successfully connected to {}", - client.basic_client.get_uri() - ))?; - - let pattern = vec!["**"]; - - match client.get_metadata(pattern).await { - Ok(metadata) => { - interface - .set_completer(Arc::new(CliCompleter::from_metadata(&metadata))); - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt("metadata", format_args!("Error {msg:?}"))?; - } - } - } - Err(err) => { - cli::print_error("connect", format!("{err}"))?; - } - } - } - }; - - loop { - if let Some(res) = interface.read_line_step(Some(TIMEOUT))? { - match res { - ReadResult::Input(line) => { - let (cmd, args) = cli::split_first_word(&line); - match cmd { - "help" => { - println!(); - for &(cmd, args, help) in CLI_COMMANDS { - println!(" {:24} {}", format!("{cmd} {args}"), help); - } - println!(); - } - "get" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - let paths = args - .split_whitespace() - .map(|path| path.to_owned()) - .collect(); - match client.get_current_values(paths).await { - Ok(data_entries) => { - cli::print_resp_ok(cmd)?; - for entry in data_entries { - if let Some(val) = entry.value { - println!( - "{}: {} {}", - entry.path, - DisplayDatapoint(val), - entry - .metadata - .and_then(|meta| meta.unit) - .map(|unit| unit.to_string()) - .unwrap_or_else(|| "".to_string()) - ); - } else { - println!("{}: NotAvailable", entry.path); - } - } - } - Err(kuksa_common::ClientError::Status(err)) => { - cli::print_resp_err(cmd, &err)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))?; - } - } - } - "token" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - match client.basic_client.set_access_token(args) { - Ok(()) => { - cli::print_info("Access token set.")?; - match client.get_metadata(vec![]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - "metadata", - format_args!("Error {msg:?}"), - )?; - } - } - } - Err(err) => { - cli::print_error(cmd, &format!("Malformed token: {err}"))? - } - } - } - "token-file" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - let token_filename = args.trim(); - match std::fs::read_to_string(token_filename) { - Ok(token) => match client.basic_client.set_access_token(token) { - Ok(()) => { - cli::print_info("Access token set.")?; - match client.get_metadata(vec![]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - Err(err) => { - cli::print_error(cmd, &format!("Malformed token: {err}"))? - } - }, - Err(err) => cli::print_error( - cmd, - &format!( - "Failed to open token file \"{token_filename}\": {err}" - ), - )?, - } - } - "set" => { - interface.add_history_unique(line.clone()); - - let (path, value) = cli::split_first_word(args); - - if value.is_empty() { - print_usage(cmd); - continue; - } - - let datapoint_entries = match client.get_metadata(vec![path]).await { - Ok(data_entries) => Some(data_entries), - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - None - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - None - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))?; - None - } - }; - - if let Some(entries) = datapoint_entries { - for entry in entries { - if let Some(metadata) = entry.metadata { - let data_value = try_into_data_value( - value, - proto::v1::DataType::from_i32(metadata.data_type) - .unwrap(), - ); - if data_value.is_err() { - println!( - "Could not parse \"{value}\" as {:?}", - proto::v1::DataType::from_i32(metadata.data_type) - .unwrap() - ); - continue; - } - - if metadata.entry_type - != proto::v1::EntryType::Actuator as i32 - { - cli::print_error( - cmd, - format!("{} is not an actuator.", path), - )?; - cli::print_info( - "If you want to provide the signal value, use `feed`.", - )?; - continue; - } - - let ts = Timestamp::from(SystemTime::now()); - let datapoints = HashMap::from([( - path.to_string().clone(), - proto::v1::Datapoint { - timestamp: Some(ts), - value: Some(data_value.unwrap()), - }, - )]); - - match client.set_current_values(datapoints).await { - Ok(_) => cli::print_resp_ok(cmd)?, - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )? - } - } - } - } - } - } - "feed" => { - interface.add_history_unique(line.clone()); - - let (path, value) = cli::split_first_word(args); - - if value.is_empty() { - print_usage(cmd); - continue; - } - - let datapoint_entries = match client.get_metadata(vec![path]).await { - Ok(data_entries) => Some(data_entries), - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - None - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - None - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))?; - None - } - }; - - if let Some(entries) = datapoint_entries { - for entry in entries { - if let Some(metadata) = entry.metadata { - let data_value = try_into_data_value( - value, - proto::v1::DataType::from_i32(metadata.data_type) - .unwrap(), - ); - if data_value.is_err() { - println!( - "Could not parse \"{}\" as {:?}", - value, - proto::v1::DataType::from_i32(metadata.data_type) - .unwrap() - ); - continue; - } - let ts = Timestamp::from(SystemTime::now()); - let datapoints = HashMap::from([( - path.to_string().clone(), - proto::v1::Datapoint { - timestamp: Some(ts), - value: Some(data_value.unwrap()), - }, - )]); - - match client.set_current_values(datapoints).await { - Ok(_) => { - cli::print_resp_ok(cmd)?; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - } - } - } - "subscribe" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - let input = args.split_whitespace().collect::>(); - - match client.subscribe(input).await { - Ok(mut subscription) => { - let iface = interface.clone(); - tokio::spawn(async move { - let sub_disp = format!("[{subscription_nbr}]"); - let sub_disp_pad = " ".repeat(sub_disp.len()); - let sub_disp_color = - format!("{}", Color::White.dimmed().paint(&sub_disp)); - - loop { - match subscription.message().await { - Ok(subscribe_resp) => { - if let Some(resp) = subscribe_resp { - // Build output before writing it - // (to avoid interleaving confusion) - use std::fmt::Write; - let mut output = String::new(); - let mut first_line = true; - for update in resp.updates { - if first_line { - first_line = false; - write!( - output, - "{} ", - &sub_disp_color, - ) - .unwrap(); - } else { - write!( - output, - "{} ", - &sub_disp_pad, - ) - .unwrap(); - } - if let Some(entry) = update.entry { - if let Some(value) = entry.value { - writeln!( - output, - "{}: {} {}", - entry.path, - DisplayDatapoint(value), - entry - .metadata - .and_then( - |meta| meta.unit - ) - .map(|unit| unit - .to_string()) - .unwrap_or_else( - || "".to_string() - ) - ) - .unwrap(); - } - } - } - write!(iface, "{output}").unwrap(); - } else { - writeln!( - iface, - "{} {}", - Color::Red.dimmed().paint(&sub_disp), - Color::White.dimmed().paint( - "Server gone. Subscription stopped" - ), - ) - .unwrap(); - break; - } - } - Err(err) => { - write!( - iface, - "{} {}", - &sub_disp_color, - Color::Red - .dimmed() - .paint(format!("Channel error: {err}")) - ) - .unwrap(); - break; - } - } - } - }); - - cli::print_resp_ok(cmd)?; - cli::print_info(format!( - "Subscription is now running in the background. Received data is identified by [{subscription_nbr}]." - ) - )?; - subscription_nbr += 1; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))? - } - } - } - "connect" => { - interface.add_history_unique(line.clone()); - if !client.basic_client.is_connected() || !args.is_empty() { - if args.is_empty() { - match client.basic_client.try_connect().await { - Ok(()) => { - cli::print_info(format!( - "[{cmd}] Successfully connected to {}", - client.basic_client.get_uri() - ))?; - } - Err(err) => { - cli::print_error(cmd, format!("{err}"))?; - } - } - } else { - match kuksa_common::to_uri(args) { - Ok(valid_uri) => { - match client - .basic_client - .try_connect_to(valid_uri) - .await - { - Ok(()) => { - cli::print_info(format!( - "[{cmd}] Successfully connected to {}", - client.basic_client.get_uri() - ))?; - } - Err(err) => { - cli::print_error(cmd, format!("{err}"))?; - } - } - } - Err(err) => { - cli::print_error( - cmd, - format!("Failed to parse endpoint address: {err}"), - )?; - } - } - }; - if client.basic_client.is_connected() { - match client.get_metadata(vec!["**"]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - }; - } - "metadata" => { - interface.add_history_unique(line.clone()); - - let paths = args.split_whitespace().collect::>(); - - if paths.is_empty() { - cli::print_info("If you want to list metadata of signals, use `metadata PATTERN`")?; - } else { - match client.get_metadata(paths).await { - Ok(metadata) => { - cli::print_resp_ok(cmd)?; - if !metadata.is_empty() { - let max_len_path = - metadata.iter().fold(0, |mut max_len, item| { - if item.path.len() > max_len { - max_len = item.path.len(); - } - max_len - }); - - cli::print_info(format!( - "{: { - cli::print_resp_err(cmd, &status)?; - continue; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)?; - continue; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - } - "quit" | "exit" => { - println!("Bye bye!"); - break; - } - "" => {} // Ignore empty input - _ => { - println!( - "Unknown command. See `help` for a list of available commands." - ); - interface.add_history_unique(line.clone()); - } - } - } - ReadResult::Eof => { - println!("Bye bye!"); - break; - } - ReadResult::Signal(sig) => { - // println!("received signal: {:?}", sig); - if sig == linefeed::Signal::Interrupt { - interface.cancel_read_line()?; - } - - let _ = writeln!(interface, "signal received: {sig:?}"); - } - } - } - } - - Ok(()) -} - -struct CliCompleter { - paths: PathPart, -} - -#[derive(Debug)] -struct PathPart { - rel_path: String, - full_path: String, - children: HashMap, -} - -impl PathPart { - fn new() -> Self { - PathPart { - rel_path: "".into(), - full_path: "".into(), - children: HashMap::new(), - } - } -} -impl CliCompleter { - fn new() -> CliCompleter { - CliCompleter { - paths: PathPart::new(), - } - } - - fn from_metadata(entries: &Vec) -> CliCompleter { - let mut root = PathPart::new(); - for entry in entries { - let mut parent = &mut root; - let parts = entry.path.split('.'); - for part in parts { - let full_path = match parent.full_path.as_str() { - "" => part.to_owned(), - _ => format!("{}.{}", parent.full_path, part), - }; - let entry = parent - .children - .entry(part.to_lowercase()) - .or_insert(PathPart { - rel_path: part.to_owned(), - full_path, - children: HashMap::new(), - }); - - parent = entry; - } - } - CliCompleter { paths: root } - } - - fn complete_entry_path(&self, word: &str) -> Option> { - if !self.paths.children.is_empty() { - let mut res = Vec::new(); - - let lowercase_word = word.to_lowercase(); - let mut parts = lowercase_word.split('.'); - let mut path = &self.paths; - loop { - match parts.next() { - Some(part) => { - match path.children.get(part) { - Some(matching_path) => { - path = matching_path; - } - None => { - // match partial - for (path_part_lower, path_spec) in &path.children { - if path_part_lower.starts_with(part) { - if !path_spec.children.is_empty() { - // This is a branch - res.push(Completion { - completion: format!("{}.", path_spec.full_path), - display: Some(format!("{}.", path_spec.rel_path)), - suffix: Suffix::None, - }); - } else { - res.push(Completion { - completion: path_spec.full_path.to_owned(), - display: Some(path_spec.rel_path.to_owned()), - suffix: Suffix::Default, - }); - } - } - } - break; - } - } - } - None => { - for path_spec in path.children.values() { - if !path_spec.children.is_empty() { - // This is a branch - res.push(Completion { - completion: format!("{}.", path_spec.full_path), - display: Some(format!("{}.", path_spec.rel_path)), - suffix: Suffix::None, - }); - } else { - res.push(Completion { - completion: path_spec.full_path.to_owned(), - display: Some(path_spec.rel_path.to_owned()), - suffix: Suffix::Default, - }); - } - } - break; - } - } - } - - res.sort_by(|a, b| a.display().cmp(&b.display())); - Some(res) - } else { - None - } - } -} - -impl Completer for CliCompleter { - fn complete( - &self, - word: &str, - prompter: &Prompter, - start: usize, - _end: usize, - ) -> Option> { - let line = prompter.buffer(); - - let mut words = line[..start].split_whitespace(); - - match words.next() { - // Complete command name - None => { - let mut compls = Vec::new(); - - for &(cmd, _, _) in CLI_COMMANDS { - if cmd.starts_with(word) { - compls.push(Completion { - completion: cmd.to_owned(), - display: None, - suffix: Suffix::default(), //Suffix::Some('('), - }); - } - } - - Some(compls) - } - // Complete command parameters - Some("set") | Some("feed") => { - if words.count() == 0 { - self.complete_entry_path(word) - } else { - None - } - } - Some("get") | Some("metadata") => self.complete_entry_path(word), - Some("subscribe") => { - if words.count() == 0 { - self.complete_entry_path(word) - } else { - None - } - } - Some("token-file") => { - let path_completer = linefeed::complete::PathCompleter; - path_completer.complete(word, prompter, start, _end) - } - _ => None, - } - } -} - -struct DisplayDataType(Option); -struct DisplayEntryType(Option); -struct DisplayDatapoint(proto::v1::Datapoint); - -fn display_array(f: &mut fmt::Formatter<'_>, array: &[T]) -> fmt::Result -where - T: fmt::Display, -{ - f.write_str("[")?; - let real_delimiter = ", "; - let mut delimiter = ""; - for value in array { - write!(f, "{delimiter}")?; - delimiter = real_delimiter; - write!(f, "{value}")?; - } - f.write_str("]") -} - -impl fmt::Display for DisplayDatapoint { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0.value { - Some(value) => match value { - proto::v1::datapoint::Value::Bool(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Int32(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Int64(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Uint32(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Uint64(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Float(value) => f.pad(&format!("{value:.2}")), - proto::v1::datapoint::Value::Double(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::String(value) => f.pad(&format!("'{value}'")), - proto::v1::datapoint::Value::StringArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::BoolArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Int32Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Int64Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Uint32Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Uint64Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::FloatArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::DoubleArray(array) => display_array(f, &array.values), - }, - None => f.pad("None"), - } - } -} - -impl From> for DisplayEntryType { - fn from(input: Option) -> Self { - DisplayEntryType(input) - } -} - -impl fmt::Display for DisplayEntryType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(entry_type) => f.pad(&format!("{entry_type:?}")), - None => f.pad("Unknown"), - } - } -} - -impl From> for DisplayDataType { - fn from(input: Option) -> Self { - DisplayDataType(input) - } -} - -impl fmt::Display for DisplayDataType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(data_type) => f.pad(&format!("{data_type:?}")), - None => f.pad("Unknown"), - } - } -} - -fn try_into_data_value( - input: &str, - data_type: proto::v1::DataType, -) -> Result { - if input == "NotAvailable" { - return Ok(proto::v1::datapoint::Value::String(input.to_string())); - } - - match data_type { - proto::v1::DataType::String => Ok(proto::v1::datapoint::Value::String(input.to_owned())), - proto::v1::DataType::StringArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::StringArray( - proto::v1::StringArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Boolean => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Bool(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::BooleanArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::BoolArray( - proto::v1::BoolArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int8 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32(value as i32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int8Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int16 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32(value as i32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int16Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int32 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int32Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int64 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int64(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int64Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int64Array( - proto::v1::Int64Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint8 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32(value as u32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint8Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint16 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32(value as u32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint16Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint32 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint32Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint64 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint64(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint64Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint64Array( - proto::v1::Uint64Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Float => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Float(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::FloatArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::FloatArray( - proto::v1::FloatArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Double => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Double(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::DoubleArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::DoubleArray( - proto::v1::DoubleArray { values: value }, - )), - Err(err) => Err(err), - }, - _ => Err(ParseError {}), - } -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_parse_values() { - // String - assert!(matches!( - try_into_data_value("test", proto::v1::DataType::String), - Ok(proto::v1::datapoint::Value::String(value)) if value == "test" - )); - - // StringArray - assert!(matches!( - try_into_data_value("[test, test2, test4]", proto::v1::DataType::StringArray), - Ok(proto::v1::datapoint::Value::StringArray(value)) if value == proto::v1::StringArray{values: vec!["test".to_string(), "test2".to_string(), "test4".to_string()]} - )); - - // Bool - assert!(matches!( - try_into_data_value("true", proto::v1::DataType::Boolean), - Ok(proto::v1::datapoint::Value::Bool(value)) if value - )); - - assert!(matches!( - try_into_data_value("false", proto::v1::DataType::Boolean), - Ok(proto::v1::datapoint::Value::Bool(value)) if !value - )); - assert!(try_into_data_value("truefalse", proto::v1::DataType::Boolean).is_err()); - // BoolArray - assert!(matches!( - try_into_data_value("[true, false, true]", proto::v1::DataType::BooleanArray), - Ok(proto::v1::datapoint::Value::BoolArray(value)) if value == proto::v1::BoolArray{values: vec![true, false, true]} - )); - - // Int8 - assert!(matches!( - try_into_data_value("100", proto::v1::DataType::Int8), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == 100 - )); - assert!(matches!( - try_into_data_value("-100", proto::v1::DataType::Int8), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == -100 - )); - assert!(try_into_data_value("300", proto::v1::DataType::Int8).is_err()); - assert!(try_into_data_value("-300", proto::v1::DataType::Int8).is_err()); - assert!(try_into_data_value("-100.1", proto::v1::DataType::Int8).is_err()); - - // Int16 - assert!(matches!( - try_into_data_value("100", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == 100 - )); - assert!(matches!( - try_into_data_value("-100", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == -100 - )); - assert!(matches!( - try_into_data_value("32000", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == 32000 - )); - assert!(matches!( - try_into_data_value("-32000", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32(value)) if value == -32000 - )); - assert!(try_into_data_value("33000", proto::v1::DataType::Int16).is_err()); - assert!(try_into_data_value("-33000", proto::v1::DataType::Int16).is_err()); - assert!(try_into_data_value("-32000.1", proto::v1::DataType::Int16).is_err()); - } - - #[test] - fn test_entry_path_completion() { - #[allow(unused_mut, unused_assignments)] - let mut metadata = vec![proto::v1::DataEntry { - path: "Vehicle.Test.Test1".into(), - value: None, - actuator_target: None, - metadata: Some(proto::v1::Metadata { - data_type: proto::v1::DataType::Boolean.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - comment: None, - deprecation: None, - unit: None, - value_restriction: None, - entry_specific: None, - description: Some("".to_string()), - }), - }]; - metadata.push(proto::v1::DataEntry { - path: "Vehicle.AnotherTest.AnotherTest1".into(), - value: None, - actuator_target: None, - metadata: Some(proto::v1::Metadata { - data_type: proto::v1::DataType::Boolean.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - comment: None, - deprecation: None, - unit: None, - value_restriction: None, - entry_specific: None, - description: Some("".to_string()), - }), - }); - metadata.push(proto::v1::DataEntry { - path: "Vehicle.AnotherTest.AnotherTest2".into(), - value: None, - actuator_target: None, - metadata: Some(proto::v1::Metadata { - data_type: proto::v1::DataType::Boolean.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - comment: None, - deprecation: None, - unit: None, - value_restriction: None, - entry_specific: None, - description: Some("".to_string()), - }), - }); - - let completer = CliCompleter::from_metadata(&metadata); - - assert_eq!(completer.paths.children.len(), 1); - assert_eq!(completer.paths.children["vehicle"].children.len(), 2); - - match completer.complete_entry_path("") { - Some(completions) => { - assert_eq!(completions.len(), 1); - assert_eq!(completions[0].display(), "Vehicle."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("v") { - Some(completions) => { - assert_eq!(completions.len(), 1); - assert_eq!(completions[0].display(), "Vehicle."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("vehicle.") { - Some(completions) => { - assert_eq!(completions.len(), 2); - assert_eq!(completions[0].display(), "AnotherTest."); - assert_eq!(completions[1].display(), "Test."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("vehicle") { - Some(completions) => { - assert_eq!(completions.len(), 2); - assert_eq!(completions[0].display(), "AnotherTest."); - assert_eq!(completions[1].display(), "Test."); - } - None => panic!("expected completions, got None"), - } - } - - #[test] - fn test_alignment() { - let max = 7; - assert_eq!("hej 1 4", format!("{: (), - Err(e) => eprintln!("Error: {}", e), - } - } else if cli.get_protocol() == CliAPI::KuksaValV1 { - let err = kuksa_cli::kuksa_main(cli.clone()).await; - match err { - Ok(_) => (), - Err(e) => eprintln!("Error: {}", e), - } - } else { - println!("Choose one protocol of either kuksa-val-v1 or sdv-databroker-v1") - } -} diff --git a/kuksa_databroker/databroker-cli/src/sdv_cli.rs b/kuksa_databroker/databroker-cli/src/sdv_cli.rs deleted file mode 100644 index 179a05568..000000000 --- a/kuksa_databroker/databroker-cli/src/sdv_cli.rs +++ /dev/null @@ -1,1333 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::sdv::databroker as proto; -use kuksa_sdv::*; - -use prost_types::Timestamp; -use tokio_stream::StreamExt; - -use std::collections::HashMap; -use std::fmt; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; - -use ansi_term::Color; - -use crate::cli::ParseError; -use crate::cli::{self, Cli}; -use linefeed::complete::{Completer, Completion, Suffix}; -use linefeed::terminal::Terminal; -use linefeed::{Command, Interface, Prompter, ReadResult}; - -const VERSION: &str = "sdv.databroker.v1"; -const TIMEOUT: Duration = Duration::from_millis(500); - -const CLI_COMMANDS: &[(&str, &str, &str)] = &[ - ("connect", "[URI]", "Connect to server"), - ("get", " [[PATH] ...]", "Get signal value(s)"), - ("set", " ", "Set actuator signal"), - ( - "subscribe", - "", - "Subscribe to signals with QUERY, if you use kuksa feature comma separated list", - ), - ("feed", " ", "Publish signal value"), - ( - "metadata", - "[PATTERN]", - "Fetch metadata. Provide PATTERN to list metadata of signals matching pattern.", - ), - ("token", "", "Use TOKEN as access token"), - ( - "token-file", - "", - "Use content of FILE as access token", - ), - ("help", "", "You're looking at it."), - ("quit", "", "Quit"), -]; - -fn print_usage(command: impl AsRef) { - for (cmd, usage, _) in CLI_COMMANDS { - if *cmd == command.as_ref() { - println!("Usage: {cmd} {usage}"); - } - } -} - -pub async fn sdv_main(_cli: Cli) -> Result<(), Box> { - let mut properties = Vec::::new(); - println!("Using {VERSION}"); - let mut cli = _cli; - - let mut subscription_nbr = 1; - - let completer = CliCompleter::new(); - let interface = Arc::new(Interface::new("client")?); - interface.set_completer(Arc::new(completer)); - - interface.define_function("enter-function", Arc::new(cli::EnterFunction)); - interface.bind_sequence("\r", Command::from_str("enter-function")); - interface.bind_sequence("\n", Command::from_str("enter-function")); - - cli::set_disconnected_prompt(&interface); - - let mut client = SDVClient::new(kuksa_common::to_uri(cli.get_server())?); - - if let Some(token_filename) = cli.get_token_file() { - let token = std::fs::read_to_string(token_filename)?; - client.basic_client.set_access_token(token)?; - } - - #[cfg(feature = "tls")] - if let Some(ca_cert_filename) = cli.get_ca_cert() { - let pem = std::fs::read(ca_cert_filename)?; - let ca_cert = tonic::transport::Certificate::from_pem(pem); - - let tls_config = tonic::transport::ClientTlsConfig::new().ca_certificate(ca_cert); - - client.basic_client.set_tls_config(tls_config); - } - - let mut connection_state_subscription = client.basic_client.subscribe_to_connection_state(); - let interface_ref = interface.clone(); - - tokio::spawn(async move { - while let Some(state) = connection_state_subscription.next().await { - match state { - Ok(state) => match state { - kuksa_common::ConnectionState::Connected => { - cli::set_connected_prompt(&interface_ref, VERSION.to_string()); - } - kuksa_common::ConnectionState::Disconnected => { - cli::set_disconnected_prompt(&interface_ref); - } - }, - Err(err) => { - cli::print_error( - "connection", - format!("Connection state subscription failed: {err}"), - ) - .unwrap_or_default(); - } - } - } - }); - - match cli.get_command() { - Some(cli::Commands::Get { paths }) => { - match client.get_datapoints(paths).await { - Ok(datapoints) => { - for (name, datapoint) in datapoints { - println!("{}: {}", name, DisplayDatapoint(datapoint),); - } - } - Err(err) => { - eprintln!("{err}"); - } - } - return Ok(()); - } - None => { - // No subcommand => run interactive client - let version = match option_env!("CARGO_PKG_VERSION") { - Some(version) => format!("v{version}"), - None => String::new(), - }; - cli::print_logo(version); - - match client.basic_client.try_connect().await { - Ok(()) => { - cli::print_info(format!( - "Successfully connected to {}", - client.basic_client.get_uri() - ))?; - - let pattern = vec![]; - - match client.get_metadata(pattern).await { - Ok(metadata) => { - interface - .set_completer(Arc::new(CliCompleter::from_metadata(&metadata))); - properties = metadata; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt("metadata", format_args!("Error {msg:?}"))?; - } - } - } - Err(err) => { - cli::print_error("connect", format!("{err}"))?; - } - } - } - }; - - loop { - if let Some(res) = interface.read_line_step(Some(TIMEOUT))? { - match res { - ReadResult::Input(line) => { - let (cmd, args) = cli::split_first_word(&line); - match cmd { - "help" => { - println!(); - for &(cmd, args, help) in CLI_COMMANDS { - println!(" {:24} {}", format!("{cmd} {args}"), help); - } - println!(); - } - "get" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - let paths = args - .split_whitespace() - .map(|path| path.to_owned()) - .collect(); - - match client.get_datapoints(paths).await { - Ok(datapoints) => { - cli::print_resp_ok(cmd)?; - for (name, datapoint) in datapoints { - println!("{}: {}", name, DisplayDatapoint(datapoint),); - } - } - Err(kuksa_common::ClientError::Status(err)) => { - cli::print_resp_err(cmd, &err)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))?; - } - } - } - "token" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - match client.basic_client.set_access_token(args) { - Ok(()) => { - cli::print_info("Access token set.")?; - match client.get_metadata(vec![]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - properties = metadata; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - "metadata", - format_args!("Error {msg:?}"), - )?; - } - } - } - Err(err) => { - cli::print_error(cmd, &format!("Malformed token: {err}"))? - } - } - } - "token-file" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - let token_filename = args.trim(); - match std::fs::read_to_string(token_filename) { - Ok(token) => match client.basic_client.set_access_token(token) { - Ok(()) => { - cli::print_info("Access token set.")?; - match client.get_metadata(vec![]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - properties = metadata; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - Err(err) => { - cli::print_error(cmd, &format!("Malformed token: {err}"))? - } - }, - Err(err) => cli::print_error( - cmd, - &format!( - "Failed to open token file \"{token_filename}\": {err}" - ), - )?, - } - } - "set" => { - interface.add_history_unique(line.clone()); - - let (path, value) = cli::split_first_word(args); - - if value.is_empty() { - print_usage(cmd); - continue; - } - - let datapoint_metadata = { - let mut datapoint_metadata = None; - for metadata in properties.iter() { - if metadata.name == path { - datapoint_metadata = Some(metadata) - } - } - datapoint_metadata - }; - - if datapoint_metadata.is_none() { - cli::print_info(format!( - "No metadata available for {path}. Needed to determine data type for serialization." - ))?; - continue; - } - - if let Some(metadata) = datapoint_metadata { - let data_value = try_into_data_value( - value, - proto::v1::DataType::from_i32(metadata.data_type).unwrap(), - ); - if data_value.is_err() { - println!( - "Could not parse \"{value}\" as {:?}", - proto::v1::DataType::from_i32(metadata.data_type).unwrap() - ); - continue; - } - - if metadata.entry_type != proto::v1::EntryType::Actuator as i32 { - cli::print_error( - cmd, - format!("{} is not an actuator.", metadata.name), - )?; - cli::print_info( - "If you want to provide the signal value, use `feed`.", - )?; - continue; - } - - let ts = Timestamp::from(SystemTime::now()); - let datapoints = HashMap::from([( - metadata.name.clone(), - proto::v1::Datapoint { - timestamp: Some(ts), - value: Some(data_value.unwrap()), - }, - )]); - - match client.set_datapoints(datapoints).await { - Ok(message) => { - if message.errors.is_empty() { - cli::print_resp_ok(cmd)?; - } else { - for (id, error) in message.errors { - match proto::v1::DatapointError::from_i32(error) { - Some(error) => { - cli::print_resp_ok(cmd)?; - println!( - "Error setting {}: {}", - id, - Color::Red.paint(format!("{error:?}")), - ); - } - None => cli::print_resp_ok_fmt( - cmd, - format_args!("Error setting id {id}"), - )?, - } - } - } - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - } - "feed" => { - interface.add_history_unique(line.clone()); - - let (path, value) = cli::split_first_word(args); - - if value.is_empty() { - print_usage(cmd); - continue; - } - - let datapoint_metadata = { - let mut datapoint_metadata = None; - for metadata in properties.iter() { - if metadata.name == path { - datapoint_metadata = Some(metadata) - } - } - datapoint_metadata - }; - - if datapoint_metadata.is_none() { - cli::print_info( - format!("No metadata available for {path}. Needed to determine data type for serialization."), - )?; - continue; - } - - if let Some(metadata) = datapoint_metadata { - let data_value = try_into_data_value( - value, - proto::v1::DataType::from_i32(metadata.data_type).unwrap(), - ); - if data_value.is_err() { - println!( - "Could not parse \"{}\" as {:?}", - value, - proto::v1::DataType::from_i32(metadata.data_type).unwrap() - ); - continue; - } - let ts = Timestamp::from(SystemTime::now()); - let datapoints = HashMap::from([( - metadata.id, - proto::v1::Datapoint { - timestamp: Some(ts), - value: Some(data_value.unwrap()), - }, - )]); - - match client.update_datapoints(datapoints).await { - Ok(message) => { - if message.errors.is_empty() { - cli::print_resp_ok(cmd)? - } else { - for (id, error) in message.errors { - let identifier = if id == metadata.id { - metadata.name.to_string() - } else { - format!("id {id}") - }; - match proto::v1::DatapointError::from_i32(error) { - Some(error) => cli::print_resp_ok_fmt( - cmd, - format_args!( - "Error providing {identifier}: {error:?}", - ), - )?, - None => cli::print_resp_ok_fmt( - cmd, - format_args!("Error providing {identifier}",), - )?, - } - } - } - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - } - "subscribe" => { - interface.add_history_unique(line.clone()); - - if args.is_empty() { - print_usage(cmd); - continue; - } - - let input = args.to_owned(); - - match client.subscribe(input).await { - Ok(mut subscription) => { - let iface = interface.clone(); - tokio::spawn(async move { - let sub_disp = format!("[{subscription_nbr}]"); - let sub_disp_pad = " ".repeat(sub_disp.len()); - let sub_disp_color = - format!("{}", Color::White.dimmed().paint(&sub_disp)); - - loop { - match subscription.message().await { - Ok(subscribe_resp) => { - if let Some(resp) = subscribe_resp { - // Build output before writing it - // (to avoid interleaving confusion) - use std::fmt::Write; - let mut output = String::new(); - let mut first_line = true; - for (name, value) in resp.fields { - if first_line { - first_line = false; - write!( - output, - "{} ", - &sub_disp_color, - ) - .unwrap(); - } else { - write!( - output, - "{} ", - &sub_disp_pad, - ) - .unwrap(); - } - writeln!( - output, - "{}: {}", - name, - DisplayDatapoint(value) - ) - .unwrap(); - } - write!(iface, "{output}").unwrap(); - } else { - writeln!( - iface, - "{} {}", - Color::Red.dimmed().paint(&sub_disp), - Color::White.dimmed().paint( - "Server gone. Subscription stopped" - ), - ) - .unwrap(); - break; - } - } - Err(err) => { - write!( - iface, - "{} {}", - &sub_disp_color, - Color::Red - .dimmed() - .paint(format!("Channel error: {err}")) - ) - .unwrap(); - break; - } - } - } - }); - - cli::print_resp_ok(cmd)?; - cli::print_info(format!( - "Subscription is now running in the background. Received data is identified by [{subscription_nbr}]." - ) - )?; - subscription_nbr += 1; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)? - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)? - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))? - } - } - } - "connect" => { - interface.add_history_unique(line.clone()); - if !client.basic_client.is_connected() || !args.is_empty() { - if args.is_empty() { - match client.basic_client.try_connect().await { - Ok(()) => { - cli::print_info(format!( - "[{cmd}] Successfully connected to {}", - client.basic_client.get_uri() - ))?; - } - Err(err) => { - cli::print_error(cmd, format!("{err}"))?; - } - } - } else { - match cli::to_uri(args) { - Ok(valid_uri) => { - match client - .basic_client - .try_connect_to(valid_uri) - .await - { - Ok(()) => { - cli::print_info(format!( - "[{cmd}] Successfully connected to {}", - client.basic_client.get_uri() - ))?; - } - Err(err) => { - cli::print_error(cmd, format!("{err}"))?; - } - } - } - Err(err) => { - cli::print_error( - cmd, - format!("Failed to parse endpoint address: {err}"), - )?; - } - } - }; - if client.basic_client.is_connected() { - match client.get_metadata(vec![]).await { - Ok(metadata) => { - interface.set_completer(Arc::new( - CliCompleter::from_metadata(&metadata), - )); - properties = metadata; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err("metadata", &status)?; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error("metadata", msg)?; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt( - cmd, - format_args!("Error {msg:?}"), - )?; - } - } - } - }; - } - "metadata" => { - interface.add_history_unique(line.clone()); - - let paths = args.split_whitespace().collect::>(); - - match client.get_metadata(vec![]).await { - Ok(mut metadata) => { - metadata.sort_by(|a, b| a.name.cmp(&b.name)); - properties = metadata; - interface.set_completer(Arc::new(CliCompleter::from_metadata( - &properties, - ))); - cli::print_resp_ok(cmd)?; - } - Err(kuksa_common::ClientError::Status(status)) => { - cli::print_resp_err(cmd, &status)?; - continue; - } - Err(kuksa_common::ClientError::Connection(msg)) => { - cli::print_error(cmd, msg)?; - continue; - } - Err(kuksa_common::ClientError::Function(msg)) => { - cli::print_resp_err_fmt(cmd, format_args!("Error {msg:?}"))?; - continue; - } - } - let mut filtered_metadata = Vec::new(); - if paths.is_empty() { - cli::print_info("If you want to list metadata of signals, use `metadata PATTERN`")?; - // filtered_metadata.extend(&properties); - } else { - for path in &paths { - let path_re = path_to_regex(path); - let filtered = - properties.iter().filter(|item| match &path_re { - Ok(re) => re.is_match(&item.name), - Err(err) => { - cli::print_info(format!("Invalid path: {err}")) - .unwrap_or_default(); - false - } - }); - filtered_metadata.extend(filtered); - } - } - - if !filtered_metadata.is_empty() { - let max_len_path = - filtered_metadata.iter().fold(0, |mut max_len, item| { - if item.name.len() > max_len { - max_len = item.name.len(); - } - max_len - }); - - cli::print_info(format!( - "{: { - println!("Bye bye!"); - break Ok(()); - } - "" => {} // Ignore empty input - _ => { - println!( - "Unknown command. See `help` for a list of available commands." - ); - interface.add_history_unique(line.clone()); - } - } - } - ReadResult::Eof => { - println!("Bye bye!"); - break Ok(()); - } - ReadResult::Signal(sig) => { - // println!("received signal: {:?}", sig); - if sig == linefeed::Signal::Interrupt { - interface.cancel_read_line()?; - } - - let _ = writeln!(interface, "signal received: {sig:?}"); - } - } - } - } -} - -struct CliCompleter { - paths: PathPart, -} - -#[derive(Debug)] -struct PathPart { - rel_path: String, - full_path: String, - children: HashMap, -} - -impl PathPart { - fn new() -> Self { - PathPart { - rel_path: "".into(), - full_path: "".into(), - children: HashMap::new(), - } - } -} -impl CliCompleter { - fn new() -> CliCompleter { - CliCompleter { - paths: PathPart::new(), - } - } - - fn from_metadata(metadata: &[proto::v1::Metadata]) -> CliCompleter { - let mut root = PathPart::new(); - for entry in metadata { - let mut parent = &mut root; - let parts = entry.name.split('.'); - for part in parts { - let full_path = match parent.full_path.as_str() { - "" => part.to_owned(), - _ => format!("{}.{}", parent.full_path, part), - }; - let entry = parent - .children - .entry(part.to_lowercase()) - .or_insert(PathPart { - rel_path: part.to_owned(), - full_path, - children: HashMap::new(), - }); - - parent = entry; - } - } - CliCompleter { paths: root } - } - - fn complete_entry_path(&self, word: &str) -> Option> { - if !self.paths.children.is_empty() { - let mut res = Vec::new(); - - let lowercase_word = word.to_lowercase(); - let mut parts = lowercase_word.split('.'); - let mut path = &self.paths; - loop { - match parts.next() { - Some(part) => { - match path.children.get(part) { - Some(matching_path) => { - path = matching_path; - } - None => { - // match partial - for (path_part_lower, path_spec) in &path.children { - if path_part_lower.starts_with(part) { - if !path_spec.children.is_empty() { - // This is a branch - res.push(Completion { - completion: format!("{}.", path_spec.full_path), - display: Some(format!("{}.", path_spec.rel_path)), - suffix: Suffix::None, - }); - } else { - res.push(Completion { - completion: path_spec.full_path.to_owned(), - display: Some(path_spec.rel_path.to_owned()), - suffix: Suffix::Default, - }); - } - } - } - break; - } - } - } - None => { - for path_spec in path.children.values() { - if !path_spec.children.is_empty() { - // This is a branch - res.push(Completion { - completion: format!("{}.", path_spec.full_path), - display: Some(format!("{}.", path_spec.rel_path)), - suffix: Suffix::None, - }); - } else { - res.push(Completion { - completion: path_spec.full_path.to_owned(), - display: Some(path_spec.rel_path.to_owned()), - suffix: Suffix::Default, - }); - } - } - break; - } - } - } - - res.sort_by(|a, b| a.display().cmp(&b.display())); - Some(res) - } else { - None - } - } -} - -impl Completer for CliCompleter { - fn complete( - &self, - word: &str, - prompter: &Prompter, - start: usize, - _end: usize, - ) -> Option> { - let line = prompter.buffer(); - - let mut words = line[..start].split_whitespace(); - - match words.next() { - // Complete command name - None => { - let mut compls = Vec::new(); - - for &(cmd, _, _) in CLI_COMMANDS { - if cmd.starts_with(word) { - compls.push(Completion { - completion: cmd.to_owned(), - display: None, - suffix: Suffix::default(), //Suffix::Some('('), - }); - } - } - - Some(compls) - } - // Complete command parameters - Some("set") | Some("feed") => { - if words.count() == 0 { - self.complete_entry_path(word) - } else { - None - } - } - Some("get") | Some("metadata") => self.complete_entry_path(word), - Some("subscribe") => match words.next() { - None => Some(vec![Completion::simple("SELECT".to_owned())]), - Some(next) => { - if next == "SELECT" { - self.complete_entry_path(word) - } else { - None - } - } - }, - Some("token-file") => { - let path_completer = linefeed::complete::PathCompleter; - path_completer.complete(word, prompter, start, _end) - } - _ => None, - } - } -} - -struct DisplayDataType(Option); -struct DisplayEntryType(Option); -// !!! ChangeType currently just exists in old API needs to be removed or added later !!! -struct DisplayChangeType(Option); -struct DisplayDatapoint(proto::v1::Datapoint); - -fn display_array(f: &mut fmt::Formatter<'_>, array: &[T]) -> fmt::Result -where - T: fmt::Display, -{ - f.write_str("[")?; - let real_delimiter = ", "; - let mut delimiter = ""; - for value in array { - write!(f, "{delimiter}")?; - delimiter = real_delimiter; - write!(f, "{value}")?; - } - f.write_str("]") -} - -impl fmt::Display for DisplayDatapoint { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0.value { - Some(value) => match value { - proto::v1::datapoint::Value::BoolValue(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::FailureValue(failure) => f.pad(&format!( - "( {:?} )", - proto::v1::datapoint::Failure::from_i32(*failure).unwrap() - )), - proto::v1::datapoint::Value::Int32Value(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Int64Value(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Uint32Value(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::Uint64Value(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::FloatValue(value) => f.pad(&format!("{value:.2}")), - proto::v1::datapoint::Value::DoubleValue(value) => f.pad(&format!("{value}")), - proto::v1::datapoint::Value::StringValue(value) => f.pad(&format!("'{value}'")), - proto::v1::datapoint::Value::StringArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::BoolArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Int32Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Int64Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Uint32Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::Uint64Array(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::FloatArray(array) => display_array(f, &array.values), - proto::v1::datapoint::Value::DoubleArray(array) => display_array(f, &array.values), - }, - None => f.pad("None"), - } - } -} - -impl From> for DisplayEntryType { - fn from(input: Option) -> Self { - DisplayEntryType(input) - } -} - -impl fmt::Display for DisplayEntryType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(entry_type) => f.pad(&format!("{entry_type:?}")), - None => f.pad("Unknown"), - } - } -} - -impl From> for DisplayDataType { - fn from(input: Option) -> Self { - DisplayDataType(input) - } -} - -impl fmt::Display for DisplayDataType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(data_type) => f.pad(&format!("{data_type:?}")), - None => f.pad("Unknown"), - } - } -} - -impl From> for DisplayChangeType { - fn from(input: Option) -> Self { - DisplayChangeType(input) - } -} -impl fmt::Display for DisplayChangeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(data_type) => f.pad(&format!("{data_type:?}")), - None => f.pad("Unknown"), - } - } -} - -fn try_into_data_value( - input: &str, - data_type: proto::v1::DataType, -) -> Result { - if input == "NotAvailable" { - return Ok(proto::v1::datapoint::Value::FailureValue( - proto::v1::datapoint::Failure::NotAvailable as i32, - )); - } - - #[allow(unreachable_patterns)] - match data_type { - proto::v1::DataType::String => { - Ok(proto::v1::datapoint::Value::StringValue(input.to_owned())) - } - proto::v1::DataType::StringArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::StringArray( - proto::v1::StringArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Bool => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::BoolValue(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::BoolArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::BoolArray( - proto::v1::BoolArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int8 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Value(value as i32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int8Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int16 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Value(value as i32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int16Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int32 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Value(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int32Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int32Array( - proto::v1::Int32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Int64 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Int64Value(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Int64Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Int64Array( - proto::v1::Int64Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint8 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Value(value as u32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint8Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint16 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Value(value as u32)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint16Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint32 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Value(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint32Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint32Array( - proto::v1::Uint32Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Uint64 => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint64Value(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::Uint64Array => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::Uint64Array( - proto::v1::Uint64Array { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Float => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::FloatValue(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::FloatArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::FloatArray( - proto::v1::FloatArray { values: value }, - )), - Err(err) => Err(err), - }, - proto::v1::DataType::Double => match input.parse::() { - Ok(value) => Ok(proto::v1::datapoint::Value::DoubleValue(value)), - Err(_) => Err(ParseError {}), - }, - proto::v1::DataType::DoubleArray => match cli::get_array_from_input(input.to_owned()) { - Ok(value) => Ok(proto::v1::datapoint::Value::DoubleArray( - proto::v1::DoubleArray { values: value }, - )), - Err(err) => Err(err), - }, - _ => Err(ParseError {}), - } -} - -fn path_to_regex(path: impl AsRef) -> Result { - let path_as_re = format!( - // Match the whole line (from left '^' to right '$') - "^{}$", - path.as_ref().replace('.', r"\.").replace('*', r"(.*)") - ); - regex::Regex::new(&path_as_re) -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_parse_values() { - // String - assert!(matches!( - try_into_data_value("test", proto::v1::DataType::String), - Ok(proto::v1::datapoint::Value::StringValue(value)) if value == "test" - )); - - // StringArray - assert!(matches!( - try_into_data_value("[test, test2, test4]", proto::v1::DataType::StringArray), - Ok(proto::v1::datapoint::Value::StringArray(value)) if value == proto::v1::StringArray{values: vec!["test".to_string(), "test2".to_string(), "test4".to_string()]} - )); - - // Bool - assert!(matches!( - try_into_data_value("true", proto::v1::DataType::Bool), - Ok(proto::v1::datapoint::Value::BoolValue(value)) if value - )); - - assert!(matches!( - try_into_data_value("false", proto::v1::DataType::Bool), - Ok(proto::v1::datapoint::Value::BoolValue(value)) if !value - )); - assert!(try_into_data_value("truefalse", proto::v1::DataType::Bool).is_err()); - // BoolArray - assert!(matches!( - try_into_data_value("[true, false, true]", proto::v1::DataType::BoolArray), - Ok(proto::v1::datapoint::Value::BoolArray(value)) if value == proto::v1::BoolArray{values: vec![true, false, true]} - )); - - // Int8 - assert!(matches!( - try_into_data_value("100", proto::v1::DataType::Int8), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == 100 - )); - assert!(matches!( - try_into_data_value("-100", proto::v1::DataType::Int8), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == -100 - )); - assert!(try_into_data_value("300", proto::v1::DataType::Int8).is_err()); - assert!(try_into_data_value("-300", proto::v1::DataType::Int8).is_err()); - assert!(try_into_data_value("-100.1", proto::v1::DataType::Int8).is_err()); - - // Int16 - assert!(matches!( - try_into_data_value("100", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == 100 - )); - assert!(matches!( - try_into_data_value("-100", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == -100 - )); - assert!(matches!( - try_into_data_value("32000", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == 32000 - )); - assert!(matches!( - try_into_data_value("-32000", proto::v1::DataType::Int16), - Ok(proto::v1::datapoint::Value::Int32Value(value)) if value == -32000 - )); - assert!(try_into_data_value("33000", proto::v1::DataType::Int16).is_err()); - assert!(try_into_data_value("-33000", proto::v1::DataType::Int16).is_err()); - assert!(try_into_data_value("-32000.1", proto::v1::DataType::Int16).is_err()); - } - - #[test] - fn test_entry_path_completion() { - #[allow(unused_mut, unused_assignments)] - let mut metadata = Vec::new(); - metadata = [ - proto::v1::Metadata { - id: 1, - name: "Vehicle.Test.Test1".into(), - data_type: proto::v1::DataType::Bool.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - change_type: proto::v1::ChangeType::OnChange.into(), - description: "".into(), - }, - proto::v1::Metadata { - id: 2, - name: "Vehicle.AnotherTest.AnotherTest1".into(), - data_type: proto::v1::DataType::Bool.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - change_type: proto::v1::ChangeType::OnChange.into(), - description: "".into(), - }, - proto::v1::Metadata { - id: 3, - name: "Vehicle.AnotherTest.AnotherTest2".into(), - data_type: proto::v1::DataType::Bool.into(), - entry_type: proto::v1::EntryType::Sensor.into(), - change_type: proto::v1::ChangeType::OnChange.into(), - description: "".into(), - }, - ] - .to_vec(); - - let completer = CliCompleter::from_metadata(&metadata); - - assert_eq!(completer.paths.children.len(), 1); - assert_eq!(completer.paths.children["vehicle"].children.len(), 2); - - match completer.complete_entry_path("") { - Some(completions) => { - assert_eq!(completions.len(), 1); - assert_eq!(completions[0].display(), "Vehicle."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("v") { - Some(completions) => { - assert_eq!(completions.len(), 1); - assert_eq!(completions[0].display(), "Vehicle."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("vehicle.") { - Some(completions) => { - assert_eq!(completions.len(), 2); - assert_eq!(completions[0].display(), "AnotherTest."); - assert_eq!(completions[1].display(), "Test."); - } - None => panic!("expected completions, got None"), - } - - match completer.complete_entry_path("vehicle") { - Some(completions) => { - assert_eq!(completions.len(), 2); - assert_eq!(completions[0].display(), "AnotherTest."); - assert_eq!(completions[1].display(), "Test."); - } - None => panic!("expected completions, got None"), - } - } - - #[test] - fn test_alignment() { - let max = 7; - assert_eq!("hej 1 4", format!("{: Result<(), Box> { - std::env::set_var("PROTOC", protobuf_src::protoc()); - tonic_build::configure() - .compile_well_known_types(false) - .protoc_arg("--experimental_allow_proto3_optional") - .compile( - &[ - "proto/sdv/databroker/v1/broker.proto", - "proto/sdv/databroker/v1/types.proto", - "proto/sdv/databroker/v1/collector.proto", - "proto/kuksa/val/v1/val.proto", - "proto/kuksa/val/v1/types.proto", - ], - &["proto"], - )?; - Ok(()) -} diff --git a/kuksa_databroker/databroker-proto/proto b/kuksa_databroker/databroker-proto/proto deleted file mode 120000 index 4d1e2d8b9..000000000 --- a/kuksa_databroker/databroker-proto/proto +++ /dev/null @@ -1 +0,0 @@ -../proto/ \ No newline at end of file diff --git a/kuksa_databroker/databroker-proto/src/lib.rs b/kuksa_databroker/databroker-proto/src/lib.rs deleted file mode 100644 index 83fe20054..000000000 --- a/kuksa_databroker/databroker-proto/src/lib.rs +++ /dev/null @@ -1,147 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -#![allow(unknown_lints)] -#![allow(clippy::derive_partial_eq_without_eq)] -pub mod sdv { - pub mod databroker { - pub mod v1 { - tonic::include_proto!("sdv.databroker.v1"); - } - } -} - -pub mod kuksa { - pub mod val { - pub mod v1 { - tonic::include_proto!("kuksa.val.v1"); - - use datapoint::Value; - use std::{any::Any, fmt::Display, str::FromStr}; - - #[derive(Debug)] - pub struct ParsingError { - message: String, - } - - impl ParsingError { - pub fn new>(message: T) -> Self { - ParsingError { - message: message.into(), - } - } - } - - impl Display for ParsingError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.message.fmt(f) - } - } - - impl std::error::Error for ParsingError {} - - impl FromStr for DataType { - type Err = ParsingError; - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "string" => Ok(DataType::String), - "string[]" => Ok(DataType::StringArray), - "bool" => Ok(DataType::Boolean), - "bool[]" => Ok(DataType::BooleanArray), - "int8" => Ok(DataType::Int8), - "int8[]" => Ok(DataType::Int8Array), - "int16" => Ok(DataType::Int16), - "int16[]" => Ok(DataType::Int16Array), - "int32" => Ok(DataType::Int32), - "int32[]" => Ok(DataType::Int32Array), - "int64" => Ok(DataType::Int64), - "int64[]" => Ok(DataType::Int64Array), - "uint8" => Ok(DataType::Uint8), - "uint8[]" => Ok(DataType::Uint8Array), - "uint16" => Ok(DataType::Uint16), - "uint16[]" => Ok(DataType::Uint16Array), - "uint32" => Ok(DataType::Uint32), - "uint32[]" => Ok(DataType::Uint32Array), - "uint64" => Ok(DataType::Uint64), - "uint64[]" => Ok(DataType::Uint64Array), - "float" => Ok(DataType::Float), - "float[]" => Ok(DataType::FloatArray), - "double" => Ok(DataType::Double), - "double[]" => Ok(DataType::DoubleArray), - _ => Err(ParsingError::new(format!("unsupported data type '{s}'"))), - } - } - } - - impl Value { - pub fn new>( - vss_type: T, - value: &str, - ) -> Result { - let dt: DataType = vss_type.into(); - match dt { - DataType::String => Ok(Value::String(value.to_string())), - DataType::Boolean => value - .parse::() - .map(Value::Bool) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Int8 => value - .parse::() - .map(|v| Value::Int32(v as i32)) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Int16 => value - .parse::() - .map(|v| Value::Int32(v as i32)) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Int32 => value - .parse::() - .map(Value::Int32) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Int64 => value - .parse::() - .map(Value::Int64) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Uint8 => value - .parse::() - .map(|v| Value::Uint32(v as u32)) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Uint16 => value - .parse::() - .map(|v| Value::Uint32(v as u32)) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Uint32 => value - .parse::() - .map(Value::Uint32) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Uint64 => value - .parse::() - .map(Value::Uint64) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Float => value - .parse::() - .map(Value::Float) - .map_err(|e| ParsingError::new(e.to_string())), - DataType::Double => value - .parse::() - .map(Value::Double) - .map_err(|e| ParsingError::new(e.to_string())), - _ => Err(ParsingError::new(format!( - "data type '{:?}' not supported for parsing string into typed value", - dt.type_id() - ))), - } - } - } - } - } -} diff --git a/kuksa_databroker/databroker/Cargo.toml b/kuksa_databroker/databroker/Cargo.toml deleted file mode 100644 index 0ca04624b..000000000 --- a/kuksa_databroker/databroker/Cargo.toml +++ /dev/null @@ -1,92 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[package] -name = "databroker" -version = "0.4.3" -authors = ["Eclipse KUKSA Project"] -edition = "2021" -license = "Apache-2.0" - -[lib] -name = "databroker" -path = "src/lib.rs" - -[dependencies] -kuksa-common = { path = "../lib/common"} -kuksa = { path = "../lib/kuksa"} -databroker-proto = { workspace = true } -tonic = { workspace = true, features = ["transport", "channel", "prost"] } -prost = { workspace = true } -prost-types = { workspace = true } -tokio = { workspace = true, features = [ - "macros", - "rt-multi-thread", - "time", - "signal", -] } -tokio-stream = { workspace = true, features = ["sync", "net"] } -tracing = "0.1.34" -tracing-subscriber = { version = "0.3.11", default-features = false, features = [ - "fmt", - "env-filter", - "ansi", -] } -clap = { workspace = true, features = [ - "std", - "env", - "derive", -] } -sqlparser = "0.16.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -jsonwebtoken = "9.1.0" -regex = "1.7.1" - -jemallocator = { version = "0.5.0", optional = true } -lazy_static = "1.4.0" -thiserror = "1.0.47" - -# VISS -axum = { version = "0.6.20", optional = true, features = ["ws"] } -futures = { version = "0.3.28", optional = true } -chrono = { version = "0.4.31", optional = true, features = ["std"] } -uuid = { version = "1.4.1", optional = true, features = ["v4"] } - -# systemd related dependency, only relevant on linux systems -[target.'cfg(target_os = "linux")'.dependencies] -sd-notify = "0.4.1" - -[features] -default = ["tls"] -tls = ["tonic/tls"] -jemalloc = ["dep:jemallocator"] -viss = ["dep:axum", "dep:chrono", "dep:futures", "dep:uuid"] -libtest = [] - -[build-dependencies] -anyhow = "1.0" -vergen = { version = "8", features = [ - "cargo", - "git", - "gitoxide", -] } - -[dev-dependencies] -anyhow = "1.0" -chrono = "^0.4" -cucumber = { version = "0.20", default-features = false, features = ["libtest", "macros"] } - -[[test]] -name = "read_write_values" -harness = false diff --git a/kuksa_databroker/databroker/Cross.toml b/kuksa_databroker/databroker/Cross.toml deleted file mode 100644 index 028e0e3be..000000000 --- a/kuksa_databroker/databroker/Cross.toml +++ /dev/null @@ -1,4 +0,0 @@ -[build.env] -passthrough = [ - "CARGO_REGISTRIES_CRATES_IO_PROTOCOL", -] diff --git a/kuksa_databroker/databroker/build.rs b/kuksa_databroker/databroker/build.rs deleted file mode 100644 index c60ccddc7..000000000 --- a/kuksa_databroker/databroker/build.rs +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022-2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use anyhow::Result; - -use vergen::EmitBuilder; - -// Extract build info (at build time) -fn main() -> Result<()> { - EmitBuilder::builder().all_cargo().all_git().emit()?; - Ok(()) -} diff --git a/kuksa_databroker/databroker/src/authorization/jwt/decoder.rs b/kuksa_databroker/databroker/src/authorization/jwt/decoder.rs deleted file mode 100644 index 872fedfab..000000000 --- a/kuksa_databroker/databroker/src/authorization/jwt/decoder.rs +++ /dev/null @@ -1,211 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::convert::TryFrom; - -use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; -use serde::Deserialize; - -use crate::permissions::{Permission, Permissions, PermissionsBuildError}; - -use super::scope; - -#[derive(Debug, PartialEq)] -pub enum Error { - PublicKeyError(String), - DecodeError(String), - ClaimsError, -} - -impl std::error::Error for Error {} -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{self:?}")) - } -} - -#[derive(Clone)] -pub struct Decoder { - decoding_key: DecodingKey, - validator: Validation, -} - -#[derive(Debug, Deserialize)] -pub struct Claims { - #[allow(dead_code)] - pub sub: String, // Subject (whom token refers to) - #[allow(dead_code)] - pub iss: String, // Issuer - #[allow(dead_code)] - pub aud: Vec, // Audience - #[allow(dead_code)] - pub iat: u64, // Issued at (as UTC timestamp) - // nbf: usize, // Optional. Not Before (as UTC timestamp) - #[allow(dead_code)] - pub exp: u64, // Expiration time (as UTC timestamp) - #[allow(dead_code)] - pub scope: String, -} - -impl Decoder { - pub fn new(public_key: impl Into) -> Result { - let decoding_key = match DecodingKey::from_rsa_pem(public_key.into().as_bytes()) { - Ok(decoding_key) => decoding_key, - Err(err) => { - return Err(Error::PublicKeyError(format!( - "Error processing public key: {err}" - ))) - } - }; - - // TODO: Make algorithm configurable. - let mut validator = Validation::new(Algorithm::RS256); - // TODO: Make "aud" configurable. - validator.set_audience(&["kuksa.val"]); - - Ok(Decoder { - decoding_key, - validator, - }) - } - - pub fn decode(&self, token: impl AsRef) -> Result { - match decode::(token.as_ref(), &self.decoding_key, &self.validator) { - Ok(token) => Ok(token.claims), - Err(err) => Err(Error::DecodeError(err.to_string())), - } - } -} - -impl TryFrom for Permissions { - type Error = Error; - - fn try_from(claims: Claims) -> Result { - let scopes = scope::parse_whitespace_separated(&claims.scope).map_err(|err| match err { - scope::Error::ParseError => Error::ClaimsError, - })?; - - let mut permissions = Permissions::builder(); - for scope in scopes { - match scope.path { - Some(path) => { - permissions = match scope.action { - scope::Action::Read => { - permissions.add_read_permission(Permission::Glob(path)) - } - scope::Action::Actuate => { - permissions.add_actuate_permission(Permission::Glob(path)) - } - scope::Action::Provide => { - permissions.add_provide_permission(Permission::Glob(path)) - } - scope::Action::Create => { - permissions.add_create_permission(Permission::Glob(path)) - } - } - } - None => { - // Empty path => all paths - permissions = match scope.action { - scope::Action::Read => permissions.add_read_permission(Permission::All), - scope::Action::Actuate => { - permissions.add_actuate_permission(Permission::All) - } - scope::Action::Provide => { - permissions.add_provide_permission(Permission::All) - } - scope::Action::Create => permissions.add_create_permission(Permission::All), - }; - } - } - } - - if let Some(expire_date) = - std::time::UNIX_EPOCH.checked_add(std::time::Duration::from_secs(claims.exp)) - { - permissions = permissions.expires_at(expire_date); - } else { - return Err(Error::ClaimsError); - } - - permissions.build().map_err(|err| match err { - PermissionsBuildError::BuildError => Error::ClaimsError, - }) - } -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_parse_token() { - let pub_key = "-----BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ScE9EKXEWVyYhzfhfvg -+LC8NseiuEjfrdFx3HKkb31bRw/SeS0Rye0KDP7uzffwreKf6wWYGxVUPYmyKC7j -Pji5MpDBGM9r3pIZSvPUFdpTE5TiRHFBxWbqPSYt954BTLq4rMu/W+oq5Pdfnugb -voYpLf0dclBl1g9KyszkDnItz3TYbWhGMbsUSfyeSPzH0IADzLoifxbc5mgiR73N -CA/4yNSpfLoqWgQ2vdTM1182sMSmxfqSgMzIMUX/tiaXGdkoKITF1sULlLyWfTo9 -79XRZ0hmUwvfzr3OjMZNoClpYSVbKY+vtxHyux9KOOtv9lPMsgYIaPXvisrsneDZ -fCS0afOfjgR96uHIe2UPSGAXru3yGziqEfpRZoxsgXaOe905ordLD5bSX14xkN7N -Cz7rxDLlxPQyxp4Vhog7p/QeUyydBpZjq2bAE5GAJtiu+XGvG8RypzJFKFQwMNsw -g1BoZVD0mb0MtU8KQmHcZIfY0FVer/CR0mUjfl1rHbtoJB+RY03lQvYNAD04ibAG -NI1RhlTziu35Xo6NDEgs9hVs9k3WrtF+ZUxhivWmP2VXhWruRakVkC1NzKGh54e5 -/KlluFbBNpWgvWZqzWo9Jr7/fzHtR0Q0IZwkxh+Vd/bUZya1uLKqP+sTcc+aTHbn -AEiqOjPq0D6X45wCzIwjILUCAwEAAQ== ------END PUBLIC KEY----- -"; - let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicmVhZDpWZWhpY2xlLlNwZWVkIn0.QyaKO-vjjzeimAAyUMjlM_jAvhlmYVguzXp76jAnW9UUiWowrXeYTa_ERVzZqxz21txq1QQmee8WtCO978w95irSRugTmlydWNjS6xPGAOCan6TEXBryrmR5FSmm6fPNrgLPhFEfcqFIQm07B286JTU98s-s2yeb6bJRpm7gOzhH5klCLxBPFYNncwdqqaT6aQD31xOcq4evooPOoV5KZFKI9WKkzOclDvto6TCLYIgnxu9Oey_IqyRAkDHybeFB7LR-1XexweRjWKleXGijpNweu6ATsbPakeVIfJ6k3IN-oKNvP6nawtBg7GeSEFYNksUUCVrIg8b0_tZi3c3E114MvdiDe7iWfRd5SDjO1f8nKiqDYy9P-hwejHntsaXLZbWSs_GNbWmi6J6pwgdM4XI3x4vx-0Otsb4zZ0tOmXjIL_tRsKA5dIlSBYEpIZq6jSXgQLN2_Ame0i--gGt4jTg1sYJHqE56BKc74HqkcvrQAZrZcoeqiKkwKcy6ofRpIQ57ghooZLkJ8BLWEV_zJgSffHBX140EEnMg1z8GAhrsbGvJ29TmXGmYyLrAhyTj_L6aNCZ1XEkbK0Yy5pco9sFGRm9nKTeFcNICogPuzbHg4xsGX_SZgUmla8Acw21AAXwuFY60_aFDUlCKZh93Z2SAruz1gfNIL43I0L8-wfw"; - - let decoder = Decoder::new(pub_key).expect("Creation of decoder should succeed"); - - match decoder.decode(token) { - Ok(claims) => { - assert_eq!(claims.scope, "read:Vehicle.Speed"); - } - Err(err) => panic!("decode should succeed but failed with:{}", err), - } - } - - #[test] - fn test_expiration_safe_addition() { - // check for expiration date that is to huge to be processed by databroker. If expiration date is later the 2424 than it shall throw an error - let pub_key = "-----BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ScE9EKXEWVyYhzfhfvg -+LC8NseiuEjfrdFx3HKkb31bRw/SeS0Rye0KDP7uzffwreKf6wWYGxVUPYmyKC7j -Pji5MpDBGM9r3pIZSvPUFdpTE5TiRHFBxWbqPSYt954BTLq4rMu/W+oq5Pdfnugb -voYpLf0dclBl1g9KyszkDnItz3TYbWhGMbsUSfyeSPzH0IADzLoifxbc5mgiR73N -CA/4yNSpfLoqWgQ2vdTM1182sMSmxfqSgMzIMUX/tiaXGdkoKITF1sULlLyWfTo9 -79XRZ0hmUwvfzr3OjMZNoClpYSVbKY+vtxHyux9KOOtv9lPMsgYIaPXvisrsneDZ -fCS0afOfjgR96uHIe2UPSGAXru3yGziqEfpRZoxsgXaOe905ordLD5bSX14xkN7N -Cz7rxDLlxPQyxp4Vhog7p/QeUyydBpZjq2bAE5GAJtiu+XGvG8RypzJFKFQwMNsw -g1BoZVD0mb0MtU8KQmHcZIfY0FVer/CR0mUjfl1rHbtoJB+RY03lQvYNAD04ibAG -NI1RhlTziu35Xo6NDEgs9hVs9k3WrtF+ZUxhivWmP2VXhWruRakVkC1NzKGh54e5 -/KlluFbBNpWgvWZqzWo9Jr7/fzHtR0Q0IZwkxh+Vd/bUZya1uLKqP+sTcc+aTHbn -AEiqOjPq0D6X45wCzIwjILUCAwEAAQ== ------END PUBLIC KEY----- -"; - let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxMzMwMTkxMTY1NzI1OTI3MjkxMywiZXhwIjoxNDM0NDUwNTM0NzIwNjk1NDE4MCwic2NvcGUiOiJwcm92aWRlIn0.HW7mVGyQL13VYPABxys0hm93zwCnF_Wnxer1OG2Qt2DExx8hlQj5RC9nbM881McMc6vebyYw4CVlKeAeI1DQAri8PeVx2xxuLKs_mtjVvqzql-DyCMikR5VYBiCsIFrFkg_oN4XtVPfhE-6IS2380tnhzhd7C1NlBs6SukCAdlURdRfHcow9NJ3WU6UlYIcT9biRSlLfMt-gKkn6LUQR1Fi77Q2SChnwbhycz7LvsifWotnP5SLdaCYpfAky5hQi9qu_qIcP-XkF5DxFWlVKe_N3FRqV1AWFapjMHRZPTS0Wwe0gMZWgaRjudXbbdTI4TTFr5HsAsSmJYsEMIixRWgsG6Hk7em_Uxu77zu9yC0Li4EivHddlUZG6nNz6XzmSgxAErmN7AIElwMxpGuaC8KpR8iEkfHoKWwr4WOLqIL-cyBLp6AIfRDm8hXOywqryrz5FsRWYeLNOruJKbYc29BC6VKS0c5H9zY2d9b6BaWxUUXCplLG5wajfVgSCbdRxZTQ0qdBv6y7J4rhplwCf8u7Ks6Pswd3wwZO-oKk3ziozjwMp4hutbUWqL_WtzCQkBkk7CxV310PUFU0tX1c1o0fPDy8VYVKymI7H_N9NyWBV5tfufmcNoe7LlLtNIMO4cU3YaUxjuxHFtHOOCBvQQC-HuIkpAkIoz45pNjx7WRI"; - - let decoder = Decoder::new(pub_key).expect("Creation of decoder should succeed"); - - match decoder.decode(token) { - Ok(claims) => match Permissions::try_from(claims) { - Ok(perm) => panic!("decode should fail but succeeded with:{:?}", perm), - Err(err) => assert_eq!(err, Error::ClaimsError), - }, - Err(err) => panic!("decode should succeed but failed with:{}", err), - } - } -} diff --git a/kuksa_databroker/databroker/src/authorization/jwt/mod.rs b/kuksa_databroker/databroker/src/authorization/jwt/mod.rs deleted file mode 100644 index 8edae8a92..000000000 --- a/kuksa_databroker/databroker/src/authorization/jwt/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -mod decoder; -mod scope; - -pub use decoder::{Claims, Decoder, Error}; diff --git a/kuksa_databroker/databroker/src/authorization/jwt/scope.rs b/kuksa_databroker/databroker/src/authorization/jwt/scope.rs deleted file mode 100644 index 263b277d1..000000000 --- a/kuksa_databroker/databroker/src/authorization/jwt/scope.rs +++ /dev/null @@ -1,282 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -#[derive(Debug)] -pub struct Scope { - pub action: Action, - pub path: Option, -} - -#[derive(Debug, Clone)] -pub enum Action { - Read, - Actuate, - Provide, - Create, -} - -#[derive(Debug)] -pub enum Error { - ParseError, -} - -pub fn parse_whitespace_separated(scope: &str) -> Result, Error> { - let regex = regex::Regex::new( - r"(?x) - ^ - (?P([^:]*)) # match action - - (?:: - (?P - ( - ( - [A-Z][a-zA-Z0-1]* - | - \* - ) - (?: - \. - ( - [A-Z][a-zA-Z0-1]* - | - \* - ) - )* - ) - ) - )? - $", - ) - .unwrap(); - - let mut parsed_scopes = Vec::new(); - for scope in scope.split_whitespace() { - let parsed_scope = match regex.captures(scope) { - Some(captures) => { - let action = match captures.name("action") { - Some(action) => match action.as_str() { - "read" => Action::Read, - "actuate" => Action::Actuate, - "provide" => Action::Provide, - "create" => Action::Create, - _ => { - // Unknown action - return Err(Error::ParseError); - } - }, - None => { - // No action specified / Unknown action - return Err(Error::ParseError); - } - }; - let path = captures.name("path").map(|path| path.as_str().to_owned()); - - Scope { action, path } - } - None => { - // Capture groups couldn't be produced - return Err(Error::ParseError); - } - }; - parsed_scopes.push(parsed_scope); - } - - Ok(parsed_scopes) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_scope_read() { - match parse_whitespace_separated("read") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - assert!(matches!(scopes[0].action, Action::Read)); - assert_eq!(scopes[0].path, None); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_read_no_path() { - match parse_whitespace_separated("read:") { - Ok(_) => { - panic!("empty path should result in error") - } - Err(Error::ParseError) => {} - } - } - - #[test] - fn test_scope_read_vehicle_test() { - match parse_whitespace_separated("read:Vehicle.Test") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Read)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.Test"); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_read_vehicle_wildcard_test() { - match parse_whitespace_separated("read:Vehicle.*.Test") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Read)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.*.Test"); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_read_vehicle_prefixed_wildcard_test() { - match parse_whitespace_separated("read:Vehicle.As*.Test") { - Ok(_) => { - panic!("wildcard is not allowed here"); - } - Err(Error::ParseError) => {} - } - } - - #[test] - fn test_scope_read_vehicle_test_wildcard_test() { - match parse_whitespace_separated("read:Vehicle.Test.*") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Read)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.Test.*"); - } - Err(_) => panic!("should not error"), - } - } - - #[test] - fn test_scope_actuate_no_path() { - match parse_whitespace_separated("actuate") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - assert!(matches!(scopes[0].action, Action::Actuate)); - assert_eq!(scopes[0].path, None); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_actuate_sep_no_path() { - match parse_whitespace_separated("actuate:") { - Ok(_) => { - panic!("empty path should result in error") - } - Err(Error::ParseError) => {} - } - } - - #[test] - fn test_scope_actuate_vehicle_test() { - match parse_whitespace_separated("actuate:Vehicle.Test") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Actuate)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.Test"); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_provide_no_path() { - match parse_whitespace_separated("provide") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - assert!(matches!(scopes[0].action, Action::Provide)); - assert_eq!(scopes[0].path, None); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_provide_sep_no_path() { - match parse_whitespace_separated("provide:") { - Ok(_) => { - panic!("empty path should result in error") - } - Err(Error::ParseError) => {} - } - } - - #[test] - fn test_scope_provide_vehicle_test() { - match parse_whitespace_separated("provide:Vehicle.Test") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Provide)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.Test"); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_create_no_path() { - match parse_whitespace_separated("create") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - assert!(matches!(scopes[0].action, Action::Create)); - assert_eq!(scopes[0].path, None); - } - Err(_) => todo!(), - } - } - - #[test] - fn test_scope_create_sep_no_path() { - match parse_whitespace_separated("create:") { - Ok(_) => { - panic!("empty path should result in error") - } - Err(Error::ParseError) => {} - } - } - - #[test] - fn test_scope_create_vehicle_test() { - match parse_whitespace_separated("create:Vehicle.*") { - Ok(scopes) => { - assert_eq!(scopes.len(), 1); - let scope = &scopes[0]; - assert!(matches!(scope.action, Action::Create)); - assert!(scope.path.is_some()); - assert_eq!(scope.path.as_deref().unwrap(), "Vehicle.*"); - } - Err(_) => todo!(), - } - } -} diff --git a/kuksa_databroker/databroker/src/authorization/mod.rs b/kuksa_databroker/databroker/src/authorization/mod.rs deleted file mode 100644 index 1edfa02fb..000000000 --- a/kuksa_databroker/databroker/src/authorization/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use thiserror::Error; - -pub mod jwt; - -#[derive(Clone)] -#[allow(clippy::large_enum_variant)] -pub enum Authorization { - Disabled, - Enabled { token_decoder: jwt::Decoder }, -} - -#[derive(Error, Debug)] -pub enum Error { - #[error("Invalid public key")] - InvalidPublicKey, -} - -impl Authorization { - pub fn new(public_key: String) -> Result { - Ok(Authorization::Enabled { - token_decoder: jwt::Decoder::new(public_key).map_err(|_| Error::InvalidPublicKey)?, - }) - } -} diff --git a/kuksa_databroker/databroker/src/broker.rs b/kuksa_databroker/databroker/src/broker.rs deleted file mode 100644 index dfa61eefb..000000000 --- a/kuksa_databroker/databroker/src/broker.rs +++ /dev/null @@ -1,3147 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use crate::permissions::{PermissionError, Permissions}; -pub use crate::types; - -use crate::query; -pub use crate::types::{ChangeType, DataType, DataValue, EntryType}; - -use tokio::sync::{broadcast, mpsc, RwLock}; -use tokio_stream::wrappers::ReceiverStream; -use tokio_stream::Stream; - -use std::collections::{HashMap, HashSet}; -use std::convert::TryFrom; -use std::sync::atomic::{AtomicI32, Ordering}; -use std::sync::Arc; -use std::time::SystemTime; - -use crate::query::{CompiledQuery, ExecutionInput}; -use crate::types::ExecutionInputImplData; -use tracing::{debug, info, warn}; - -use crate::glob; - -#[derive(Debug)] -pub enum UpdateError { - NotFound, - WrongType, - OutOfBounds, - UnsupportedType, - PermissionDenied, - PermissionExpired, -} - -#[derive(Debug, Clone)] -pub enum ReadError { - NotFound, - PermissionDenied, - PermissionExpired, -} - -#[derive(Debug, PartialEq)] -pub enum RegistrationError { - ValidationError, - PermissionDenied, - PermissionExpired, -} - -#[derive(Debug, Clone)] -pub struct Metadata { - pub id: i32, - pub path: String, - pub data_type: DataType, - pub entry_type: EntryType, - pub change_type: ChangeType, - pub description: String, - pub allowed: Option, - pub unit: Option, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct Datapoint { - pub ts: SystemTime, - pub source_ts: Option, - pub value: DataValue, -} - -#[derive(Debug, Clone)] -pub struct Entry { - pub datapoint: Datapoint, - pub lag_datapoint: Datapoint, - pub actuator_target: Option, - pub metadata: Metadata, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Field { - Datapoint, - ActuatorTarget, - MetadataUnit, -} - -#[derive(Default)] -pub struct Database { - next_id: AtomicI32, - path_to_id: HashMap, - entries: HashMap, -} - -#[derive(Default)] -pub struct Subscriptions { - query_subscriptions: Vec, - change_subscriptions: Vec, -} - -#[derive(Debug, Clone)] -pub struct QueryResponse { - pub fields: Vec, -} - -#[derive(Debug, Clone)] -pub struct QueryField { - pub name: String, - pub value: DataValue, -} - -#[derive(Debug)] -pub struct ChangeNotification { - pub update: EntryUpdate, - pub fields: HashSet, -} - -#[derive(Debug, Default)] -pub struct EntryUpdates { - pub updates: Vec, -} - -#[derive(Debug)] -pub enum QueryError { - CompilationError(String), - InternalError, -} - -#[derive(Debug)] -pub enum SubscriptionError { - NotFound, - InvalidInput, - InternalError, -} - -#[derive(Clone)] -pub struct DataBroker { - database: Arc>, - subscriptions: Arc>, - version: String, - shutdown_trigger: broadcast::Sender<()>, -} - -pub struct QuerySubscription { - query: query::CompiledQuery, - sender: mpsc::Sender, - permissions: Permissions, -} - -pub struct ChangeSubscription { - entries: HashMap>, - sender: mpsc::Sender, - permissions: Permissions, -} - -#[derive(Debug)] -pub struct NotificationError {} - -#[derive(Debug, Clone, Default)] -pub struct EntryUpdate { - pub path: Option, - - pub datapoint: Option, - - // Actuator target is wrapped in an additional Option<> in - // order to be able to convey "update it to None" which would - // mean setting it to `Some(None)`. - pub actuator_target: Option>, // only for actuators - - // Metadata - pub entry_type: Option, - pub data_type: Option, - pub description: Option, - // allowed is wrapped in an additional Option<> in - // order to be able to convey "update it to None" which would - // mean setting it to `Some(None)`. - pub allowed: Option>, - pub unit: Option, -} - -impl Entry { - pub fn diff(&self, mut update: EntryUpdate) -> EntryUpdate { - if let Some(datapoint) = &update.datapoint { - if self.metadata.change_type != ChangeType::Continuous { - // TODO: Compare timestamps as well? - if datapoint.value == self.datapoint.value { - update.datapoint = None; - } - } - } - - // TODO: Implement for .path - // .entry_type - // .data_type - // .description - // .allowed - - update - } - - pub fn validate(&self, update: &EntryUpdate) -> Result<(), UpdateError> { - if let Some(datapoint) = &update.datapoint { - self.validate_value(&datapoint.value)?; - self.validate_allowed(&datapoint.value)?; - } - if let Some(Some(actuatortarget)) = &update.actuator_target { - self.validate_value(&actuatortarget.value)?; - self.validate_allowed(&actuatortarget.value)?; - } - if let Some(Some(updated_allowed)) = update.allowed.clone() { - if Some(updated_allowed.clone()) != self.metadata.allowed { - self.validate_allowed_type(&Some(updated_allowed))?; - } - } - Ok(()) - } - - pub fn validate_allowed_type(&self, allowed: &Option) -> Result<(), UpdateError> { - if let Some(allowed_values) = allowed { - match (allowed_values, &self.metadata.data_type) { - (DataValue::BoolArray(_allowed_values), DataType::Bool) => Ok(()), - (DataValue::StringArray(_allowed_values), DataType::String) => Ok(()), - (DataValue::Int32Array(_allowed_values), DataType::Int32) => Ok(()), - (DataValue::Int64Array(_allowed_values), DataType::Int64) => Ok(()), - (DataValue::Uint32Array(_allowed_values), DataType::Uint32) => Ok(()), - (DataValue::Uint64Array(_allowed_values), DataType::Uint64) => Ok(()), - (DataValue::FloatArray(_allowed_values), DataType::Float) => Ok(()), - (DataValue::DoubleArray(_allowed_values), DataType::Double) => Ok(()), - (DataValue::BoolArray(_allowed_values), DataType::BoolArray) => Ok(()), - (DataValue::StringArray(_allowed_values), DataType::StringArray) => Ok(()), - (DataValue::Int32Array(_allowed_values), DataType::Int32Array) => Ok(()), - (DataValue::Int64Array(_allowed_values), DataType::Int64Array) => Ok(()), - (DataValue::Uint32Array(_allowed_values), DataType::Uint32Array) => Ok(()), - (DataValue::Uint64Array(_allowed_values), DataType::Uint64Array) => Ok(()), - (DataValue::FloatArray(_allowed_values), DataType::FloatArray) => Ok(()), - (DataValue::DoubleArray(_allowed_values), DataType::DoubleArray) => Ok(()), - _ => Err(UpdateError::WrongType {}), - } - } else { - // it is allowed to set allowed to None - Ok(()) - } - } - - fn validate_allowed(&self, value: &DataValue) -> Result<(), UpdateError> { - // check if allowed value - if let Some(allowed_values) = &self.metadata.allowed { - match (allowed_values, value) { - (DataValue::BoolArray(allowed_values), DataValue::Bool(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::DoubleArray(allowed_values), DataValue::Double(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::FloatArray(allowed_values), DataValue::Float(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::Int32Array(allowed_values), DataValue::Int32(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::Int64Array(allowed_values), DataValue::Int64(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::StringArray(allowed_values), DataValue::String(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::Uint32Array(allowed_values), DataValue::Uint32(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::Uint64Array(allowed_values), DataValue::Uint64(value)) => { - match allowed_values.contains(value) { - true => Ok(()), - false => Err(UpdateError::OutOfBounds), - } - } - (DataValue::BoolArray(allowed_values), DataValue::BoolArray(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::DoubleArray(allowed_values), DataValue::DoubleArray(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::FloatArray(allowed_values), DataValue::FloatArray(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::Int32Array(allowed_values), DataValue::Int32Array(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::Int64Array(allowed_values), DataValue::Int64Array(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::StringArray(allowed_values), DataValue::StringArray(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::Uint32Array(allowed_values), DataValue::Uint32Array(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - (DataValue::Uint64Array(allowed_values), DataValue::Uint64Array(value)) => { - for item in value { - match allowed_values.contains(item) { - true => (), - false => return Err(UpdateError::OutOfBounds), - } - } - Ok(()) - } - _ => Err(UpdateError::UnsupportedType), - } - } else { - Ok(()) - } - } - - fn validate_value(&self, value: &DataValue) -> Result<(), UpdateError> { - // Not available is always valid - if value == &DataValue::NotAvailable { - return Ok(()); - } - - // Validate value - match self.metadata.data_type { - DataType::Bool => match value { - DataValue::Bool(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::String => match value { - DataValue::String(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Int8 => match value { - DataValue::Int32(value) => match i8::try_from(*value) { - Ok(_) => Ok(()), - Err(_) => Err(UpdateError::OutOfBounds), - }, - _ => Err(UpdateError::WrongType), - }, - DataType::Int16 => match value { - DataValue::Int32(value) => match i16::try_from(*value) { - Ok(_) => Ok(()), - Err(_) => Err(UpdateError::OutOfBounds), - }, - _ => Err(UpdateError::WrongType), - }, - DataType::Int32 => match value { - DataValue::Int32(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - - DataType::Int64 => match value { - DataValue::Int64(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Uint8 => match value { - DataValue::Uint32(value) => match u8::try_from(*value) { - Ok(_) => Ok(()), - Err(_) => Err(UpdateError::OutOfBounds), - }, - _ => Err(UpdateError::WrongType), - }, - DataType::Uint16 => match value { - DataValue::Uint32(value) => match u16::try_from(*value) { - Ok(_) => Ok(()), - Err(_) => Err(UpdateError::OutOfBounds), - }, - _ => Err(UpdateError::WrongType), - }, - DataType::Uint32 => match value { - DataValue::Uint32(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Uint64 => match value { - DataValue::Uint64(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Float => match value { - DataValue::Float(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Double => match value { - DataValue::Double(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::BoolArray => match value { - DataValue::BoolArray(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::StringArray => match value { - DataValue::StringArray(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Int8Array => match &value { - DataValue::Int32Array(array) => { - let mut out_of_bounds = false; - for value in array { - match i8::try_from(*value) { - Ok(_) => {} - Err(_) => { - out_of_bounds = true; - break; - } - } - } - if out_of_bounds { - Err(UpdateError::OutOfBounds) - } else { - Ok(()) - } - } - _ => Err(UpdateError::WrongType), - }, - DataType::Int16Array => match &value { - DataValue::Int32Array(array) => { - let mut out_of_bounds = false; - for value in array { - match i16::try_from(*value) { - Ok(_) => {} - Err(_) => { - out_of_bounds = true; - break; - } - } - } - if out_of_bounds { - Err(UpdateError::OutOfBounds) - } else { - Ok(()) - } - } - _ => Err(UpdateError::WrongType), - }, - DataType::Int32Array => match value { - DataValue::Int32Array(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Int64Array => match value { - DataValue::Int64Array(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Uint8Array => match &value { - DataValue::Uint32Array(array) => { - let mut out_of_bounds = false; - for value in array { - match u8::try_from(*value) { - Ok(_) => {} - Err(_) => { - out_of_bounds = true; - break; - } - } - } - if out_of_bounds { - Err(UpdateError::OutOfBounds) - } else { - Ok(()) - } - } - _ => Err(UpdateError::WrongType), - }, - DataType::Uint16Array => match &value { - DataValue::Uint32Array(array) => { - let mut out_of_bounds = false; - for value in array { - match u16::try_from(*value) { - Ok(_) => {} - Err(_) => { - out_of_bounds = true; - break; - } - } - } - if out_of_bounds { - Err(UpdateError::OutOfBounds) - } else { - Ok(()) - } - } - _ => Err(UpdateError::WrongType), - }, - DataType::Uint32Array => match value { - DataValue::Uint32Array(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::Uint64Array => match value { - DataValue::Uint64Array(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::FloatArray => match value { - DataValue::FloatArray(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - DataType::DoubleArray => match value { - DataValue::DoubleArray(_) => Ok(()), - _ => Err(UpdateError::WrongType), - }, - } - } - - pub fn apply_lag_after_execute(&mut self) { - self.lag_datapoint = self.datapoint.clone(); - } - - pub fn apply(&mut self, update: EntryUpdate) -> HashSet { - let mut changed = HashSet::new(); - if let Some(datapoint) = update.datapoint { - self.lag_datapoint = self.datapoint.clone(); - self.datapoint = datapoint; - changed.insert(Field::Datapoint); - } - if let Some(actuator_target) = update.actuator_target { - self.actuator_target = actuator_target; - changed.insert(Field::ActuatorTarget); - } - - if let Some(updated_allowed) = update.allowed { - if updated_allowed != self.metadata.allowed { - self.metadata.allowed = updated_allowed; - } - } - - // TODO: Apply the other fields as well - - changed - } -} - -#[derive(Debug)] -pub enum SuccessfulUpdate { - NoChange, - ValueChanged, -} - -impl Subscriptions { - pub fn add_query_subscription(&mut self, subscription: QuerySubscription) { - self.query_subscriptions.push(subscription) - } - - pub fn add_change_subscription(&mut self, subscription: ChangeSubscription) { - self.change_subscriptions.push(subscription) - } - - pub async fn notify( - &self, - changed: Option<&HashMap>>, - db: &Database, - ) -> Result>, NotificationError> { - let mut error = None; - let mut lag_updates: HashMap = HashMap::new(); - for sub in &self.query_subscriptions { - match sub.notify(changed, db).await { - Ok(None) => {} - Ok(Some(input)) => { - for x in input.get_fields() { - if x.1.lag_value != x.1.value && !lag_updates.contains_key(x.0) { - lag_updates.insert(x.0.clone(), ()); - } - } - } - Err(err) => error = Some(err), - } - } - - for sub in &self.change_subscriptions { - match sub.notify(changed, db).await { - Ok(_) => {} - Err(err) => error = Some(err), - } - } - - match error { - Some(err) => Err(err), - None => { - if !lag_updates.is_empty() { - Ok(Some(lag_updates)) - } else { - Ok(None) - } - } - } - } - - pub fn clear(&mut self) { - self.query_subscriptions.clear(); - self.change_subscriptions.clear(); - } - - pub fn cleanup(&mut self) { - self.query_subscriptions.retain(|sub| { - if sub.sender.is_closed() { - info!("Subscriber gone: removing subscription"); - false - } else { - true - } - }); - self.change_subscriptions.retain(|sub| { - if sub.sender.is_closed() { - info!("Subscriber gone: removing subscription"); - false - } else { - true - } - }); - } -} - -impl ChangeSubscription { - async fn notify( - &self, - changed: Option<&HashMap>>, - db: &Database, - ) -> Result<(), NotificationError> { - let db_read = db.authorized_read_access(&self.permissions); - match changed { - Some(changed) => { - let mut matches = false; - for (id, changed_fields) in changed { - if let Some(fields) = self.entries.get(id) { - if !fields.is_disjoint(changed_fields) { - matches = true; - break; - } - } - } - if matches { - // notify - let notifications = { - let mut notifications = EntryUpdates::default(); - - for (id, changed_fields) in changed { - if let Some(fields) = self.entries.get(id) { - if !fields.is_disjoint(changed_fields) { - match db_read.get_entry_by_id(*id) { - Ok(entry) => { - let mut update = EntryUpdate::default(); - let mut notify_fields = HashSet::new(); - // TODO: Perhaps make path optional - update.path = Some(entry.metadata.path.clone()); - if changed_fields.contains(&Field::Datapoint) - && fields.contains(&Field::Datapoint) - { - update.datapoint = Some(entry.datapoint.clone()); - notify_fields.insert(Field::Datapoint); - } - if changed_fields.contains(&Field::ActuatorTarget) - && fields.contains(&Field::ActuatorTarget) - { - update.actuator_target = - Some(entry.actuator_target.clone()); - notify_fields.insert(Field::ActuatorTarget); - } - // fill unit field always - update.unit = entry.metadata.unit.clone(); - notifications.updates.push(ChangeNotification { - update, - fields: notify_fields, - }); - } - Err(_) => { - debug!("notify: could not find entry with id {}", id) - } - } - } - } - } - notifications - }; - if notifications.updates.is_empty() { - Ok(()) - } else { - match self.sender.send(notifications).await { - Ok(()) => Ok(()), - Err(_) => Err(NotificationError {}), - } - } - } else { - Ok(()) - } - } - None => { - let notifications = { - let mut notifications = EntryUpdates::default(); - - for (id, fields) in &self.entries { - match db_read.get_entry_by_id(*id) { - Ok(entry) => { - let mut update = EntryUpdate::default(); - let mut notify_fields = HashSet::new(); - // TODO: Perhaps make path optional - update.path = Some(entry.metadata.path.clone()); - if fields.contains(&Field::Datapoint) { - update.datapoint = Some(entry.datapoint.clone()); - notify_fields.insert(Field::Datapoint); - } - if fields.contains(&Field::ActuatorTarget) { - update.actuator_target = Some(entry.actuator_target.clone()); - notify_fields.insert(Field::ActuatorTarget); - } - notifications.updates.push(ChangeNotification { - update, - fields: notify_fields, - }); - } - Err(_) => { - debug!("notify: could not find entry with id {}", id) - } - } - } - notifications - }; - match self.sender.send(notifications).await { - Ok(()) => Ok(()), - Err(_) => Err(NotificationError {}), - } - } - } - } -} - -impl QuerySubscription { - fn find_in_db_and_add( - &self, - name: &String, - db: &DatabaseReadAccess, - input: &mut query::ExecutionInputImpl, - ) { - match db.get_entry_by_path(name) { - Ok(entry) => { - input.add( - name.to_owned(), - ExecutionInputImplData { - value: entry.datapoint.value.to_owned(), - lag_value: entry.lag_datapoint.value.to_owned(), - }, - ); - } - Err(_) => { - // TODO: This should probably generate an error - input.add( - name.to_owned(), - ExecutionInputImplData { - value: DataValue::NotAvailable, - lag_value: DataValue::NotAvailable, - }, - ) - } - } - } - fn check_if_changes_match( - query: &CompiledQuery, - changed_origin: Option<&HashMap>>, - db: &DatabaseReadAccess, - ) -> bool { - match changed_origin { - Some(changed) => { - for (id, fields) in changed { - if let Some(metadata) = db.get_metadata_by_id(*id) { - if query.input_spec.contains(&metadata.path) - && fields.contains(&Field::Datapoint) - { - return true; - } - if !query.subquery.is_empty() { - for sub in query.subquery.iter() { - if QuerySubscription::check_if_changes_match( - sub, - changed_origin, - db, - ) { - return true; - } - } - } - } - } - } - None => { - // Always generate input if `changed` is None - return true; - } - } - false - } - fn generate_input_list( - &self, - query: &CompiledQuery, - db: &DatabaseReadAccess, - input: &mut query::ExecutionInputImpl, - ) { - for name in query.input_spec.iter() { - self.find_in_db_and_add(name, db, input); - } - if !query.subquery.is_empty() { - for sub in query.subquery.iter() { - self.generate_input_list(sub, db, input) - } - } - } - fn generate_input( - &self, - changed: Option<&HashMap>>, - db: &DatabaseReadAccess, - ) -> Option { - let id_used_in_query = QuerySubscription::check_if_changes_match(&self.query, changed, db); - - if id_used_in_query { - let mut input = query::ExecutionInputImpl::new(); - self.generate_input_list(&self.query, db, &mut input); - Some(input) - } else { - None - } - } - - async fn notify( - &self, - changed: Option<&HashMap>>, - db: &Database, - ) -> Result, NotificationError> { - let db_read = db.authorized_read_access(&self.permissions); - - match self.generate_input(changed, &db_read) { - Some(input) => - // Execute query (if anything queued) - { - match self.query.execute(&input) { - Ok(result) => match result { - Some(fields) => match self - .sender - .send(QueryResponse { - fields: fields - .iter() - .map(|e| QueryField { - name: e.0.to_owned(), - value: e.1.to_owned(), - }) - .collect(), - }) - .await - { - Ok(()) => Ok(Some(input)), - Err(_) => Err(NotificationError {}), - }, - None => Ok(None), - }, - Err(e) => { - // TODO: send error to subscriber - debug!("{:?}", e); - Ok(None) // no cleanup needed - } - } - } - None => Ok(None), - } - } -} - -pub struct DatabaseReadAccess<'a, 'b> { - db: &'a Database, - permissions: &'b Permissions, -} - -pub struct DatabaseWriteAccess<'a, 'b> { - db: &'a mut Database, - permissions: &'b Permissions, -} - -pub enum EntryReadAccess<'a> { - Entry(&'a Entry), - Err(&'a Metadata, ReadError), -} - -impl<'a> EntryReadAccess<'a> { - pub fn datapoint(&self) -> Result<&Datapoint, ReadError> { - match self { - Self::Entry(entry) => Ok(&entry.datapoint), - Self::Err(_, err) => Err(err.clone()), - } - } - - pub fn actuator_target(&self) -> Result<&Option, ReadError> { - match self { - Self::Entry(entry) => Ok(&entry.actuator_target), - Self::Err(_, err) => Err(err.clone()), - } - } - - pub fn metadata(&self) -> &Metadata { - match self { - Self::Entry(entry) => &entry.metadata, - Self::Err(metadata, _) => metadata, - } - } -} - -impl<'a> EntryReadAccess<'a> { - fn new(entry: &'a Entry, permissions: &Permissions) -> Self { - match permissions.can_read(&entry.metadata.path) { - Ok(()) => Self::Entry(entry), - Err(PermissionError::Denied) => Self::Err(&entry.metadata, ReadError::PermissionDenied), - Err(PermissionError::Expired) => { - Self::Err(&entry.metadata, ReadError::PermissionExpired) - } - } - } -} - -pub struct EntryReadIterator<'a, 'b> { - inner: std::collections::hash_map::Values<'a, i32, Entry>, - permissions: &'b Permissions, -} - -impl<'a, 'b> Iterator for EntryReadIterator<'a, 'b> { - type Item = EntryReadAccess<'a>; - - #[inline] - fn next(&mut self) -> Option { - self.inner - .next() - .map(|entry| EntryReadAccess::new(entry, self.permissions)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl<'a, 'b> DatabaseReadAccess<'a, 'b> { - pub fn get_entry_by_id(&self, id: i32) -> Result<&Entry, ReadError> { - match self.db.entries.get(&id) { - Some(entry) => match self.permissions.can_read(&entry.metadata.path) { - Ok(_) => Ok(entry), - Err(PermissionError::Denied) => Err(ReadError::PermissionDenied), - Err(PermissionError::Expired) => Err(ReadError::PermissionExpired), - }, - None => Err(ReadError::NotFound), - } - } - - pub fn get_entry_by_path(&self, path: impl AsRef) -> Result<&Entry, ReadError> { - match self.db.path_to_id.get(path.as_ref()) { - Some(id) => self.get_entry_by_id(*id), - None => Err(ReadError::NotFound), - } - } - - pub fn get_metadata_by_id(&self, id: i32) -> Option<&Metadata> { - self.db.entries.get(&id).map(|entry| &entry.metadata) - } - - pub fn get_metadata_by_path(&self, path: &str) -> Option<&Metadata> { - let id = self.db.path_to_id.get(path)?; - self.get_metadata_by_id(*id) - } - - pub fn iter_entries(&self) -> EntryReadIterator { - EntryReadIterator { - inner: self.db.entries.values(), - permissions: self.permissions, - } - } -} - -impl<'a, 'b> DatabaseWriteAccess<'a, 'b> { - pub fn update_by_path( - &mut self, - path: &str, - update: EntryUpdate, - ) -> Result, UpdateError> { - match self.db.path_to_id.get(path) { - Some(id) => self.update(*id, update), - None => Err(UpdateError::NotFound), - } - } - - pub fn update_entry_lag_to_be_equal(&mut self, path: &str) -> Result<(), UpdateError> { - match self.db.path_to_id.get(path) { - Some(id) => match self.db.entries.get_mut(id) { - Some(entry) => { - entry.apply_lag_after_execute(); - Ok(()) - } - None => Err(UpdateError::NotFound), - }, - None => Err(UpdateError::NotFound), - } - } - - pub fn update(&mut self, id: i32, update: EntryUpdate) -> Result, UpdateError> { - match self.db.entries.get_mut(&id) { - Some(entry) => { - if update.path.is_some() - || update.entry_type.is_some() - || update.data_type.is_some() - || update.description.is_some() - { - return Err(UpdateError::PermissionDenied); - } - match ( - &update.datapoint, - self.permissions.can_write_datapoint(&entry.metadata.path), - ) { - (Some(_), Err(PermissionError::Denied)) => { - return Err(UpdateError::PermissionDenied) - } - (Some(_), Err(PermissionError::Expired)) => { - return Err(UpdateError::PermissionExpired) - } - (_, _) => { - // Ok - } - } - - match ( - &update.actuator_target, - self.permissions - .can_write_actuator_target(&entry.metadata.path), - ) { - (Some(_), Err(PermissionError::Denied)) => { - return Err(UpdateError::PermissionDenied) - } - (Some(_), Err(PermissionError::Expired)) => { - return Err(UpdateError::PermissionExpired) - } - (_, _) => {} - } - - // Reduce update to only include changes - let update = entry.diff(update); - // Validate update - match entry.validate(&update) { - Ok(_) => { - let changed_fields = entry.apply(update); - Ok(changed_fields) - } - Err(err) => Err(err), - } - } - None => Err(UpdateError::NotFound), - } - } - - #[allow(clippy::too_many_arguments)] - pub fn add( - &mut self, - name: String, - data_type: DataType, - change_type: ChangeType, - entry_type: EntryType, - description: String, - allowed: Option, - datapoint: Option, - unit: Option, - ) -> Result { - if !glob::is_valid_path(name.as_str()) { - return Err(RegistrationError::ValidationError); - } - - self.permissions - .can_create(&name) - .map_err(|err| match err { - PermissionError::Denied => RegistrationError::PermissionDenied, - PermissionError::Expired => RegistrationError::PermissionExpired, - })?; - - if let Some(id) = self.db.path_to_id.get(&name) { - // It already exists - return Ok(*id); - }; - - let temp_id = 0; - - let mut new_entry = Entry { - metadata: Metadata { - id: temp_id, - path: name.clone(), - data_type, - change_type, - entry_type, - description, - allowed, - unit, - }, - datapoint: match datapoint.clone() { - Some(datapoint) => datapoint, - None => Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::NotAvailable, - }, - }, - lag_datapoint: match datapoint { - Some(datapoint) => datapoint, - None => Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::NotAvailable, - }, - }, - actuator_target: None, - }; - - new_entry - .validate_allowed_type(&new_entry.metadata.allowed) - .map_err(|_err| RegistrationError::ValidationError)?; - - // Get next id (and bump it) - let id = self.db.next_id.fetch_add(1, Ordering::SeqCst); - - // Map name -> id - self.db.path_to_id.insert(name, id); - - new_entry.metadata.id = id; - - // Add entry (mapped by id) - self.db.entries.insert(id, new_entry); - - // Return the id - Ok(id) - } -} - -impl Database { - pub fn new() -> Self { - Self { - next_id: Default::default(), - path_to_id: Default::default(), - entries: Default::default(), - } - } - - pub fn authorized_read_access<'a, 'b>( - &'a self, - permissions: &'b Permissions, - ) -> DatabaseReadAccess<'a, 'b> { - DatabaseReadAccess { - db: self, - permissions, - } - } - - pub fn authorized_write_access<'a, 'b>( - &'a mut self, - permissions: &'b Permissions, - ) -> DatabaseWriteAccess<'a, 'b> { - DatabaseWriteAccess { - db: self, - permissions, - } - } -} - -impl<'a, 'b> query::CompilationInput for DatabaseReadAccess<'a, 'b> { - fn get_datapoint_type(&self, path: &str) -> Result { - match self.get_metadata_by_path(path) { - Some(metadata) => Ok(metadata.data_type.to_owned()), - None => Err(query::CompilationError::UnknownField(path.to_owned())), - } - } -} - -pub struct AuthorizedAccess<'a, 'b> { - broker: &'a DataBroker, - permissions: &'b Permissions, -} - -impl<'a, 'b> AuthorizedAccess<'a, 'b> { - #[allow(clippy::too_many_arguments)] - pub async fn add_entry( - &self, - name: String, - data_type: DataType, - change_type: ChangeType, - entry_type: EntryType, - description: String, - allowed: Option, - unit: Option, - ) -> Result { - self.broker - .database - .write() - .await - .authorized_write_access(self.permissions) - .add( - name, - data_type, - change_type, - entry_type, - description, - allowed, - None, - unit, - ) - } - - pub async fn with_read_lock(&self, f: impl FnOnce(&DatabaseReadAccess) -> T) -> T { - f(&self - .broker - .database - .read() - .await - .authorized_read_access(self.permissions)) - } - - pub async fn get_id_by_path(&self, name: &str) -> Option { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_metadata_by_path(name) - .map(|metadata| metadata.id) - } - - pub async fn get_datapoint(&self, id: i32) -> Result { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_entry_by_id(id) - .map(|entry| entry.datapoint.clone()) - } - - pub async fn get_datapoint_by_path(&self, name: &str) -> Result { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_entry_by_path(name) - .map(|entry| entry.datapoint.clone()) - } - - pub async fn get_metadata(&self, id: i32) -> Option { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_metadata_by_id(id) - .cloned() - } - - pub async fn get_metadata_by_path(&self, path: &str) -> Option { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_metadata_by_path(path) - .cloned() - } - - pub async fn get_entry_by_path(&self, path: &str) -> Result { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_entry_by_path(path) - .cloned() - } - - pub async fn get_entry_by_id(&self, id: i32) -> Result { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .get_entry_by_id(id) - .cloned() - } - - pub async fn for_each_entry(&self, f: impl FnMut(EntryReadAccess)) { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .iter_entries() - .for_each(f) - } - - pub async fn map_entries(&self, f: impl FnMut(EntryReadAccess) -> T) -> Vec { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .iter_entries() - .map(f) - .collect() - } - - pub async fn filter_map_entries( - &self, - f: impl FnMut(EntryReadAccess) -> Option, - ) -> Vec { - self.broker - .database - .read() - .await - .authorized_read_access(self.permissions) - .iter_entries() - .filter_map(f) - .collect() - } - - pub async fn update_entries( - &self, - updates: impl IntoIterator, - ) -> Result<(), Vec<(i32, UpdateError)>> { - let mut errors = Vec::new(); - let mut db = self.broker.database.write().await; - let mut db_write = db.authorized_write_access(self.permissions); - let mut lag_updates: HashMap = HashMap::new(); - - let cleanup_needed = { - let changed = { - let mut changed = HashMap::>::new(); - for (id, update) in updates { - debug!("setting id {} to {:?}", id, update); - match db_write.update(id, update) { - Ok(changed_fields) => { - if !changed_fields.is_empty() { - changed.insert(id, changed_fields); - } - } - Err(err) => { - errors.push((id, err)); - } - } - } - changed - }; - // Downgrade to reader (to allow other readers) while holding on - // to a read lock in order to ensure a consistent state while - // notifying subscribers (no writes in between) - let db = db.downgrade(); - - // Notify - match self - .broker - .subscriptions - .read() - .await - .notify(Some(&changed), &db) - .await - { - Ok(None) => false, - Ok(Some(lag_updates_)) => { - lag_updates = lag_updates_.clone(); - false - } - Err(_) => true, // Cleanup needed - } - }; - - if !lag_updates.is_empty() { - let mut db = self.broker.database.write().await; - let mut db_write = db.authorized_write_access(self.permissions); - for x in lag_updates { - if db_write.update_entry_lag_to_be_equal(x.0.as_str()).is_ok() {} - } - } - - // Cleanup closed subscriptions - if cleanup_needed { - self.broker.subscriptions.write().await.cleanup(); - } - - // Return errors if any - if !errors.is_empty() { - Err(errors) - } else { - Ok(()) - } - } - - pub async fn subscribe( - &self, - valid_entries: HashMap>, - ) -> Result, SubscriptionError> { - if valid_entries.is_empty() { - return Err(SubscriptionError::InvalidInput); - } - - let (sender, receiver) = mpsc::channel(10); - let subscription = ChangeSubscription { - entries: valid_entries, - sender, - permissions: self.permissions.clone(), - }; - - { - // Send everything subscribed to in an initial notification - let db = self.broker.database.read().await; - if subscription.notify(None, &db).await.is_err() { - warn!("Failed to create initial notification"); - } - } - - self.broker - .subscriptions - .write() - .await - .add_change_subscription(subscription); - - let stream = ReceiverStream::new(receiver); - Ok(stream) - } - - pub async fn subscribe_query( - &self, - query: &str, - ) -> Result, QueryError> { - let db_read = self.broker.database.read().await; - let db_read_access = db_read.authorized_read_access(self.permissions); - - let compiled_query = query::compile(query, &db_read_access); - - match compiled_query { - Ok(compiled_query) => { - let (sender, receiver) = mpsc::channel(10); - - let subscription = QuerySubscription { - query: compiled_query, - sender, - permissions: self.permissions.clone(), - }; - - // Send the initial execution of query - match subscription.notify(None, &db_read).await { - Ok(_) => self - .broker - .subscriptions - .write() - .await - .add_query_subscription(subscription), - Err(_) => return Err(QueryError::InternalError), - }; - - let stream = ReceiverStream::new(receiver); - Ok(stream) - } - Err(e) => Err(QueryError::CompilationError(format!("{e:?}"))), - } - } -} - -impl DataBroker { - pub fn new(version: impl Into) -> Self { - let (shutdown_trigger, _) = broadcast::channel::<()>(1); - - DataBroker { - database: Default::default(), - subscriptions: Default::default(), - version: version.into(), - shutdown_trigger, - } - } - - pub fn authorized_access<'a, 'b>( - &'a self, - permissions: &'b Permissions, - ) -> AuthorizedAccess<'a, 'b> { - AuthorizedAccess { - broker: self, - permissions, - } - } - - pub fn start_housekeeping_task(&self) { - info!("Starting housekeeping task"); - let subscriptions = self.subscriptions.clone(); - tokio::spawn(async move { - let mut interval = tokio::time::interval(std::time::Duration::from_secs(1)); - - loop { - interval.tick().await; - // Cleanup dropped subscriptions - subscriptions.write().await.cleanup(); - } - }); - } - - pub async fn shutdown(&self) { - // Drain subscriptions - let mut subscriptions = self.subscriptions.write().await; - subscriptions.clear(); - - // Signal shutdown - let _ = self.shutdown_trigger.send(()); - } - - pub fn get_shutdown_trigger(&self) -> broadcast::Receiver<()> { - self.shutdown_trigger.subscribe() - } - - pub fn get_version(&self) -> &str { - &self.version - } -} - -impl Default for DataBroker { - fn default() -> Self { - Self::new("") - } -} - -#[cfg(test)] -mod tests { - use crate::permissions; - - use super::*; - use tokio_stream::StreamExt; - - #[tokio::test] - async fn test_register_datapoint() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - Some(DataValue::BoolArray(Vec::from([true]))), - Some("kg".to_string()), - ) - .await - .expect("Register datapoint should succeed"); - - { - match broker.get_entry_by_id(id1).await { - Ok(entry) => { - assert_eq!(entry.metadata.id, id1); - assert_eq!(entry.metadata.path, "test.datapoint1"); - assert_eq!(entry.metadata.data_type, DataType::Bool); - assert_eq!(entry.metadata.description, "Test datapoint 1"); - assert_eq!( - entry.metadata.allowed, - Some(DataValue::BoolArray(Vec::from([true]))) - ); - assert_eq!(entry.metadata.unit, Some("kg".to_string())); - } - Err(_) => { - panic!("datapoint should exist"); - } - } - } - - let id2 = broker - .add_entry( - "test.datapoint2".to_owned(), - DataType::String, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 2".to_owned(), - None, - Some("km".to_string()), - ) - .await - .expect("Register datapoint should succeed"); - - { - match broker.get_entry_by_id(id2).await { - Ok(entry) => { - assert_eq!(entry.metadata.id, id2); - assert_eq!(entry.metadata.path, "test.datapoint2"); - assert_eq!(entry.metadata.data_type, DataType::String); - assert_eq!(entry.metadata.description, "Test datapoint 2"); - assert_eq!(entry.metadata.allowed, None); - assert_eq!(entry.metadata.unit, Some("km".to_string())); - } - Err(_) => { - panic!("no metadata returned"); - } - } - } - - let id3 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1 (modified)".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - assert_eq!(id3, id1); - } - - #[tokio::test] - async fn test_register_invalid_type() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - if broker - .add_entry( - "test.signal3".to_owned(), - DataType::String, - ChangeType::OnChange, - EntryType::Sensor, - "Test signal 3".to_owned(), - Some(DataValue::Int32Array(Vec::from([1, 2, 3, 4]))), - None, - ) - .await - .is_ok() - { - panic!("Entry should not register successfully"); - } else { - // everything fine, should not succed to register because allowed is Int32Array and data_type is String - } - } - - #[tokio::test] - async fn test_get_set_datapoint() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let id2 = broker - .add_entry( - "test.datapoint2".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Actuator, - "Test datapoint 2".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - // Data point exists with value NotAvailable - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::NotAvailable); - } - Err(_) => { - panic!("data point expected to exist"); - } - } - - match broker.get_entry_by_id(id2).await { - Ok(entry) => { - assert_eq!(entry.datapoint.value, DataValue::NotAvailable); - assert_eq!(entry.actuator_target, None) - } - Err(_) => { - panic!("data point expected to exist"); - } - } - - let time1 = SystemTime::now(); - - match broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: time1, - source_ts: None, - value: DataValue::Bool(true), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(_) => { - panic!("should not have been able to set int32 typed datapoint to boolean value") - } - Err(e) => match e[0] { - (id, UpdateError::WrongType) => assert_eq!(id, id1), - _ => panic!( - "should have reported wrong type but got error of type {:?}", - e - ), - }, - } - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: time1, - source_ts: None, - value: DataValue::Int32(100), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - let time2 = SystemTime::now(); - broker - .update_entries([( - id2, - EntryUpdate { - path: None, - datapoint: None, - actuator_target: Some(Some(Datapoint { - ts: time2, - source_ts: None, - value: DataValue::Bool(true), - })), - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #2"); - - // Data point exists with value 100 - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(100)); - assert_eq!(datapoint.ts, time1); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint1 to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - - match broker.get_entry_by_id(id2).await { - Ok(entry) => match entry.actuator_target { - Some(datapoint) => { - assert_eq!(datapoint.value, DataValue::Bool(true)); - assert_eq!(datapoint.ts, time2); - } - None => { - panic!("data point expected to exist"); - } - }, - Err(ReadError::NotFound) => { - panic!("expected datapoint2 to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_get_set_allowed_values() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - Some(DataValue::Int32Array(vec![100])), - None, - ) - .await - .expect("Register datapoint should succeed"); - - if broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(1), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: Some(Some(DataValue::Int32Array(vec![100]))), - unit: None, - }, - )]) - .await - .is_ok() - { - panic!("Setting int32 value of 1 should fail because it is not in the allowed values"); - } else { - // everything fine should fail because trying to set a value which is not in allowed values - } - - if broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: None, - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: Some(Some(DataValue::BoolArray(vec![true]))), - unit: None, - }, - )]) - .await - .is_ok() - { - panic!("Setting allowed to a BoolArray should fail because data_type is int32"); - } else { - // everything fine should fail because trying to set array of type Bool does not match data_type - } - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: None, - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: Some(None), - unit: None, - }, - )]) - .await - .expect("setting allowed for entry #1"); - - let time1 = SystemTime::now(); - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: time1, - source_ts: None, - value: DataValue::Int32(1), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(1)); - assert_eq!(datapoint.ts, time1); - } - Err(ReadError::NotFound) => { - panic!("data point 1 expected to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to have access to data point 1"); - } - } - } - - #[tokio::test] - async fn test_subscribe_query_and_get() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut stream = broker - .subscribe_query("SELECT test.datapoint1") - .await - .expect("Setup subscription"); - - // Expect an initial query response - // No value has been set yet, so value should be NotAvailable - match stream.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::NotAvailable); - } - None => { - panic!("did not expect stream end") - } - } - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(101), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - // Value has been set, expect the next item in stream to match. - match stream.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::Int32(101)); - } - None => { - panic!("did not expect stream end") - } - } - - // Check that the data point has been stored as well - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(101)); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_multi_subscribe() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut subscription1 = broker - .subscribe_query("SELECT test.datapoint1") - .await - .expect("setup first subscription"); - - let mut subscription2 = broker - .subscribe_query("SELECT test.datapoint1") - .await - .expect("setup second subscription"); - - // Expect an initial query response - // No value has been set yet, so value should be NotAvailable - match subscription1.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::NotAvailable); - } - None => { - panic!("did not expect stream end") - } - } - - // Expect an initial query response - // No value has been set yet, so value should be NotAvailable - match subscription2.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::NotAvailable); - } - None => { - panic!("did not expect stream end") - } - } - - for i in 0..100 { - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(i), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - if let Some(query_resp) = subscription1.next().await { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - if let DataValue::Int32(value) = query_resp.fields[0].value { - assert_eq!(value, i); - } else { - panic!("expected test.datapoint1 to contain a value"); - } - } else { - panic!("did not expect end of stream"); - } - - if let Some(query_resp) = subscription2.next().await { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - if let DataValue::Int32(value) = query_resp.fields[0].value { - assert_eq!(value, i); - } else { - panic!("expected test.datapoint1 to contain a value"); - } - } else { - panic!("did not expect end of stream"); - } - } - } - - #[tokio::test] - async fn test_subscribe_after_new_registration() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut subscription = broker - .subscribe_query("SELECT test.datapoint1") - .await - .expect("Setup subscription"); - - // Expect an initial query response - // No value has been set yet, so value should be NotAvailable - match subscription.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::NotAvailable); - } - None => { - panic!("did not expect stream end") - } - } - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(200), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - match subscription.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::Int32(200)); - } - None => { - panic!("did not expect stream end") - } - } - - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(200)); - } - Err(ReadError::NotFound) => { - panic!("datapoint expected to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - - let id2 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1 (new description)".to_owned(), - None, - None, - ) - .await - .expect("Registration should succeed"); - - assert_eq!(id1, id2, "Re-registration should result in the same id"); - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(102), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1 (second time)"); - - match subscription.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 1); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::Int32(102)); - } - None => { - panic!("did not expect stream end") - } - } - - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(102)); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_subscribe_set_multiple() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let id2 = broker - .add_entry( - "test.datapoint2".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 2".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut subscription = broker - .subscribe_query("SELECT test.datapoint1, test.datapoint2") - .await - .expect("setup first subscription"); - - // Expect an initial query response - // No value has been set yet, so value should be NotAvailable - match subscription.next().await { - Some(query_resp) => { - assert_eq!(query_resp.fields.len(), 2); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - assert_eq!(query_resp.fields[0].value, DataValue::NotAvailable); - assert_eq!(query_resp.fields[1].name, "test.datapoint2"); - assert_eq!(query_resp.fields[1].value, DataValue::NotAvailable); - } - None => { - panic!("did not expect stream end") - } - } - - for i in 0..10 { - broker - .update_entries([ - ( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(-i), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - ), - ( - id2, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(i), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - ), - ]) - .await - .expect("setting datapoint #1"); - } - - for i in 0..10 { - if let Some(query_resp) = subscription.next().await { - assert_eq!(query_resp.fields.len(), 2); - assert_eq!(query_resp.fields[0].name, "test.datapoint1"); - if let DataValue::Int32(value) = query_resp.fields[0].value { - assert_eq!(value, -i); - } else { - panic!("expected test.datapoint1 to contain a values"); - } - assert_eq!(query_resp.fields[1].name, "test.datapoint2"); - if let DataValue::Int32(value) = query_resp.fields[1].value { - assert_eq!(value, i); - } else { - panic!("expected test.datapoint2 to contain a values"); - } - } else { - panic!("did not expect end of stream"); - } - } - } - - #[tokio::test] - async fn test_bool_array() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::BoolArray, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - None, - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::BoolArray(vec![true, true, false, true]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(()) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::BoolArray(vec![true, true, false, true]) - ); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_string_array() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::StringArray, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - None, - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - ]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(_) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - ]) - ); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_string_array_allowed_values() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::StringArray, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - Some(DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - ])), - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - ]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(_) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - ]) - ); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - - // check if duplicate is working - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - String::from("yes"), - ]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(_) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - String::from("yes"), - ]) - ); - } - Err(ReadError::NotFound) => panic!("Expected datapoint to exist"), - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("Expected to have access to datapoint") - } - } - - if broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::StringArray(vec![ - String::from("yes"), - String::from("no"), - String::from("maybe"), - String::from("nah"), - String::from("true"), - ]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .is_ok() - { - panic!("Expected set_datapoints to fail because string(true) not in allowed values") - } else { - // everything fine vlaue string(true) not in the allowed values - } - } - - #[tokio::test] - async fn test_int8_array() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::Int8Array, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - None, - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::Int32Array(vec![10, 20, 30, 40]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(()) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - if broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::Int32Array(vec![100, 200, 300, 400]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .is_ok() - { - panic!("Expected set_datapoints to fail ( with Err() ), instead got: Ok(())",) - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!(datapoint.value, DataValue::Int32Array(vec![10, 20, 30, 40])); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_uint8_array() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::Uint8Array, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - None, - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::Uint32Array(vec![10, 20, 30, 40]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(()) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - if broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::Uint32Array(vec![100, 200, 300, 400]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .is_ok() - { - panic!("Expected set_datapoints to fail ( with Err() ), instead got: Ok(())",) - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::Uint32Array(vec![10, 20, 30, 40]) - ); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_float_array() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id = broker - .add_entry( - "Vehicle.TestArray".to_owned(), - DataType::FloatArray, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test array".to_owned(), - None, - None, - ) - .await - .unwrap(); - - let ts = std::time::SystemTime::now(); - match broker - .update_entries([( - id, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts, - source_ts: None, - value: DataValue::FloatArray(vec![10.0, 20.0, 30.0, 40.0]), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - { - Ok(()) => {} - Err(e) => { - panic!( - "Expected set_datapoints to succeed ( with Ok(()) ), instead got: Err({:?})", - e - ) - } - } - - match broker.get_datapoint(id).await { - Ok(datapoint) => { - assert_eq!(datapoint.ts, ts); - assert_eq!( - datapoint.value, - DataValue::FloatArray(vec![10.0, 20.0, 30.0, 40.0]) - ); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_subscribe_and_get() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "test.datapoint1".to_owned(), - DataType::Int32, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut stream = broker - .subscribe(HashMap::from([(id1, HashSet::from([Field::Datapoint]))])) - .await - .expect("subscription should succeed"); - - // Stream should yield initial notification with current values i.e. NotAvailable - match stream.next().await { - Some(next) => { - assert_eq!(next.updates.len(), 1); - assert_eq!( - next.updates[0].update.path, - Some("test.datapoint1".to_string()) - ); - assert_eq!( - next.updates[0].update.datapoint.as_ref().unwrap().value, - DataValue::NotAvailable - ); - } - None => { - panic!("did not expect stream end") - } - } - - broker - .update_entries([( - id1, - EntryUpdate { - path: None, - datapoint: Some(Datapoint { - ts: SystemTime::now(), - source_ts: None, - value: DataValue::Int32(101), - }), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]) - .await - .expect("setting datapoint #1"); - - // Value has been set, expect the next item in stream to match. - match stream.next().await { - Some(next) => { - assert_eq!(next.updates.len(), 1); - assert_eq!( - next.updates[0].update.path, - Some("test.datapoint1".to_string()) - ); - assert_eq!( - next.updates[0].update.datapoint.as_ref().unwrap().value, - DataValue::Int32(101) - ); - } - None => { - panic!("did not expect stream end") - } - } - - // Check that the data point has been stored as well - match broker.get_datapoint(id1).await { - Ok(datapoint) => { - assert_eq!(datapoint.value, DataValue::Int32(101)); - } - Err(ReadError::NotFound) => { - panic!("expected datapoint to exist"); - } - Err(ReadError::PermissionDenied | ReadError::PermissionExpired) => { - panic!("expected to be authorized"); - } - } - } - - #[tokio::test] - async fn test_metadata_for_each() { - let db = DataBroker::default(); - let broker = db.authorized_access(&permissions::ALLOW_ALL); - - let id1 = broker - .add_entry( - "Vehicle.Test1".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test signal".to_owned(), - None, - None, - ) - .await - .unwrap(); - let id2 = broker - .add_entry( - "Vehicle.Test2".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Sensor, - "Run of the mill test signal".to_owned(), - None, - None, - ) - .await - .unwrap(); - - // No permissions - let permissions = Permissions::builder().build().unwrap(); - let broker = db.authorized_access(&permissions); - let metadata = broker.map_entries(|entry| entry.metadata().clone()).await; - for entry in metadata { - match entry.path.as_str() { - "Vehicle.Test1" => assert_eq!(entry.id, id1), - "Vehicle.Test2" => assert_eq!(entry.id, id2), - _ => panic!("Unexpected metadata entry"), - } - } - } - - #[tokio::test] - async fn test_register_invalid_and_valid_path() { - let broker = DataBroker::default(); - let broker = broker.authorized_access(&permissions::ALLOW_ALL); - - let error = broker - .add_entry( - "test. signal:3".to_owned(), - DataType::String, - ChangeType::OnChange, - EntryType::Sensor, - "Test signal 3".to_owned(), - Some(DataValue::Int32Array(Vec::from([1, 2, 3, 4]))), - None, - ) - .await - .unwrap_err(); - assert_eq!(error, RegistrationError::ValidationError); - - let id = broker - .add_entry( - "Vehicle._kuksa.databroker.GitVersion.Do_you_not_like_smörgåstårta.tschö_mit_ö.東京_Москва_r#true".to_owned(), - DataType::Bool, - ChangeType::OnChange, - EntryType::Sensor, - "Test datapoint".to_owned(), - Some(DataValue::BoolArray(Vec::from([true]))), - None, - ) - .await - .expect("Register datapoint should succeed"); - { - match broker.get_entry_by_id(id).await { - Ok(entry) => { - assert_eq!(entry.metadata.id, id); - assert_eq!(entry.metadata.path, "Vehicle._kuksa.databroker.GitVersion.Do_you_not_like_smörgåstårta.tschö_mit_ö.東京_Москва_r#true"); - assert_eq!(entry.metadata.data_type, DataType::Bool); - assert_eq!(entry.metadata.description, "Test datapoint"); - assert_eq!( - entry.metadata.allowed, - Some(DataValue::BoolArray(Vec::from([true]))) - ); - } - Err(_) => { - panic!("no metadata returned"); - } - } - } - } -} diff --git a/kuksa_databroker/databroker/src/glob.rs b/kuksa_databroker/databroker/src/glob.rs deleted file mode 100644 index b156f6808..000000000 --- a/kuksa_databroker/databroker/src/glob.rs +++ /dev/null @@ -1,1544 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use lazy_static::lazy_static; -use regex::Regex; - -#[derive(Debug)] -pub enum Error { - RegexError, -} - -pub fn to_regex_string(glob: &str) -> String { - // Construct regular expression - - // Make sure we match the whole thing - // Start from the beginning - let mut re = String::from("^"); - - if glob.eq("*") { - return re.replace('^', "\x00"); - } else if glob.is_empty() { - return re; - } - - let mut regex_string = glob.replace('.', "\\."); - - if !glob.contains('*') { - regex_string += "(?:\\..+)?"; - } else { - if glob.starts_with("**.") { - regex_string = regex_string.replace("**\\.", ".+\\."); - } else if glob.starts_with("*.") { - regex_string = regex_string.replace("*\\.", "[^.\\s\\:]+\\."); - } - - if glob.ends_with(".*") { - regex_string = regex_string.replace("\\.*", "\\.[^.\\s\\:]+"); - } else if glob.ends_with(".**") { - regex_string = regex_string.replace("\\.**", "\\..*"); - } - - if glob.contains(".**.") { - regex_string = regex_string.replace("\\.**", "[\\.[^.\\s\\:]+]*"); - } - - if glob.contains(".*.") { - regex_string = regex_string.replace("\\.*", "\\.[^.\\s\\:]+"); - } - } - - re.push_str(regex_string.as_str()); - - // And finally, make sure we match until EOL - re.push('$'); - - re -} - -pub fn to_regex(glob: &str) -> Result { - let re = to_regex_string(glob); - Regex::new(&re).map_err(|_err| Error::RegexError) -} - -lazy_static! { - static ref REGEX_VALID_PATTERN: regex::Regex = regex::Regex::new( - r"(?x) - ^ # anchor at start (only match full paths) - # At least one subpath (consisting of either of three): - (?: - [^\.\s\:]+ # Any character except :, whitespace and . - | - \* # An asterisk - | - \*\* # A double asterisk - ) - # which can be followed by ( separator + another subpath ) - # repeated any number of times - (?: - \. # Separator, literal dot - (?: - [^\.\s\:]+ # Any character except :, whitespace and . - | - \* # An asterisk - | - \*\* # A double asterisk - )+ - )* - $ # anchor at end (to match only full paths) - ", - ) - .expect("regex compilation (of static pattern) should always succeed"); -} - -pub fn is_valid_pattern(input: &str) -> bool { - REGEX_VALID_PATTERN.is_match(input) -} - -lazy_static! { - static ref REGEX_VALID_PATH: regex::Regex = regex::Regex::new( - r"(?x) - ^ # anchor at start (only match full paths) - # At least one subpath (consisting of either of three): - (?: - [^\.\s\:\*]+ # Any character except :, whitespace and . - ) - # which can be followed by ( separator + another subpath ) - # repeated any number of times - (?: - \. # Separator, literal dot - (?: - [^\.\s\:\*]+ # Any character except :, whitespace and . - )+ - )* - $ # anchor at end (to match only full paths) - ", - ) - .expect("regex compilation (of static path) should always succeed"); -} - -pub fn is_valid_path(input: &str) -> bool { - REGEX_VALID_PATH.is_match(input) -} - -#[cfg(test)] -mod tests { - use super::*; - - static ALL_SIGNALS: &[&str] = &[ - "Vehicle._kuksa.databroker.GitVersion", - "Vehicle._kuksa.databroker.CargoVersion", - "Vehicle._kuksa.databroker.GitVersion", - "Vehicle.ADAS.ABS.IsEnabled", - "Vehicle.ADAS.ABS.IsEngaged", - "Vehicle.ADAS.ABS.IsError", - "Vehicle.ADAS.ActiveAutonomyLevel", - "Vehicle.ADAS.CruiseControl.IsActive", - "Vehicle.ADAS.CruiseControl.IsEnabled", - "Vehicle.ADAS.CruiseControl.IsError", - "Vehicle.ADAS.CruiseControl.SpeedSet", - "Vehicle.ADAS.DMS.IsEnabled", - "Vehicle.ADAS.DMS.IsError", - "Vehicle.ADAS.DMS.IsWarning", - "Vehicle.ADAS.EBA.IsEnabled", - "Vehicle.ADAS.EBA.IsEngaged", - "Vehicle.ADAS.EBA.IsError", - "Vehicle.ADAS.EBD.IsEnabled", - "Vehicle.ADAS.EBD.IsEngaged", - "Vehicle.ADAS.EBD.IsError", - "Vehicle.ADAS.ESC.IsEnabled", - "Vehicle.ADAS.ESC.IsEngaged", - "Vehicle.ADAS.ESC.IsError", - "Vehicle.ADAS.ESC.IsStrongCrossWindDetected", - "Vehicle.ADAS.ESC.RoadFriction.LowerBound", - "Vehicle.ADAS.ESC.RoadFriction.MostProbable", - "Vehicle.ADAS.ESC.RoadFriction.UpperBound", - "Vehicle.ADAS.LaneDepartureDetection.IsEnabled", - "Vehicle.ADAS.LaneDepartureDetection.IsError", - "Vehicle.ADAS.LaneDepartureDetection.IsWarning", - "Vehicle.ADAS.ObstacleDetection.IsEnabled", - "Vehicle.ADAS.ObstacleDetection.IsError", - "Vehicle.ADAS.ObstacleDetection.IsWarning", - "Vehicle.ADAS.PowerOptimizeLevel", - "Vehicle.ADAS.SupportedAutonomyLevel", - "Vehicle.ADAS.TCS.IsEnabled", - "Vehicle.ADAS.TCS.IsEngaged", - "Vehicle.ADAS.TCS.IsError", - "Vehicle.Acceleration.Lateral", - "Vehicle.Acceleration.Longitudinal", - "Vehicle.Acceleration.Vertical", - "Vehicle.AngularVelocity.Pitch", - "Vehicle.AngularVelocity.Roll", - "Vehicle.AngularVelocity.Yaw", - "Vehicle.AverageSpeed", - "Vehicle.Body.BodyType", - "Vehicle.Body.Hood.IsOpen", - "Vehicle.Body.Horn.IsActive", - "Vehicle.Body.Lights.Backup.IsDefect", - "Vehicle.Body.Lights.Backup.IsOn", - "Vehicle.Body.Lights.Beam.High.IsDefect", - "Vehicle.Body.Lights.Beam.High.IsOn", - "Vehicle.Body.Lights.Beam.Low.IsDefect", - "Vehicle.Body.Lights.Beam.Low.IsOn", - "Vehicle.Body.Lights.Brake.IsActive", - "Vehicle.Body.Lights.Brake.IsDefect", - "Vehicle.Body.Lights.DirectionIndicator.Left.IsDefect", - "Vehicle.Body.Lights.DirectionIndicator.Left.IsSignaling", - "Vehicle.Body.Lights.DirectionIndicator.Right.IsDefect", - "Vehicle.Body.Lights.DirectionIndicator.Right.IsSignaling", - "Vehicle.Body.Lights.Fog.Front.IsDefect", - "Vehicle.Body.Lights.Fog.Front.IsOn", - "Vehicle.Body.Lights.Fog.Rear.IsDefect", - "Vehicle.Body.Lights.Fog.Rear.IsOn", - "Vehicle.Body.Lights.Hazard.IsDefect", - "Vehicle.Body.Lights.Hazard.IsSignaling", - "Vehicle.Body.Lights.IsHighBeamSwitchOn", - "Vehicle.Body.Lights.LicensePlate.IsDefect", - "Vehicle.Body.Lights.LicensePlate.IsOn", - "Vehicle.Body.Lights.LightSwitch", - "Vehicle.Body.Lights.Parking.IsDefect", - "Vehicle.Body.Lights.Parking.IsOn", - "Vehicle.Body.Lights.Running.IsDefect", - "Vehicle.Body.Lights.Running.IsOn", - "Vehicle.Body.Mirrors.DriverSide.IsHeatingOn", - "Vehicle.Body.Mirrors.DriverSide.Pan", - "Vehicle.Body.Mirrors.DriverSide.Tilt", - "Vehicle.Body.Mirrors.PassengerSide.IsHeatingOn", - "Vehicle.Body.Mirrors.PassengerSide.Pan", - "Vehicle.Body.Mirrors.PassengerSide.Tilt", - "Vehicle.Body.PowerOptimizeLevel", - "Vehicle.Body.Raindetection.Intensity", - "Vehicle.Body.RearMainSpoilerPosition", - "Vehicle.Body.RefuelPosition", - "Vehicle.Body.Trunk.Front.IsLightOn", - "Vehicle.Body.Trunk.Front.IsLocked", - "Vehicle.Body.Trunk.Front.IsOpen", - "Vehicle.Body.Trunk.Rear.IsLightOn", - "Vehicle.Body.Trunk.Rear.IsLocked", - "Vehicle.Body.Trunk.Rear.IsOpen", - "Vehicle.Body.Windshield.Front.IsHeatingOn", - "Vehicle.Body.Windshield.Front.WasherFluid.IsLevelLow", - "Vehicle.Body.Windshield.Front.WasherFluid.Level", - "Vehicle.Body.Windshield.Front.Wiping.Intensity", - "Vehicle.Body.Windshield.Front.Wiping.IsWipersWorn", - "Vehicle.Body.Windshield.Front.Wiping.Mode", - "Vehicle.Body.Windshield.Front.Wiping.System.ActualPosition", - "Vehicle.Body.Windshield.Front.Wiping.System.DriveCurrent", - "Vehicle.Body.Windshield.Front.Wiping.System.Frequency", - "Vehicle.Body.Windshield.Front.Wiping.System.IsBlocked", - "Vehicle.Body.Windshield.Front.Wiping.System.IsEndingWipeCycle", - "Vehicle.Body.Windshield.Front.Wiping.System.IsOverheated", - "Vehicle.Body.Windshield.Front.Wiping.System.IsPositionReached", - "Vehicle.Body.Windshield.Front.Wiping.System.IsWiperError", - "Vehicle.Body.Windshield.Front.Wiping.System.IsWiping", - "Vehicle.Body.Windshield.Front.Wiping.System.Mode", - "Vehicle.Body.Windshield.Front.Wiping.System.TargetPosition", - "Vehicle.Body.Windshield.Front.Wiping.WiperWear", - "Vehicle.Body.Windshield.Rear.IsHeatingOn", - "Vehicle.Body.Windshield.Rear.WasherFluid.IsLevelLow", - "Vehicle.Body.Windshield.Rear.WasherFluid.Level", - "Vehicle.Body.Windshield.Rear.Wiping.Intensity", - "Vehicle.Body.Windshield.Rear.Wiping.IsWipersWorn", - "Vehicle.Body.Windshield.Rear.Wiping.Mode", - "Vehicle.Body.Windshield.Rear.Wiping.System.ActualPosition", - "Vehicle.Body.Windshield.Rear.Wiping.System.DriveCurrent", - "Vehicle.Body.Windshield.Rear.Wiping.System.Frequency", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsBlocked", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsEndingWipeCycle", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsOverheated", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsPositionReached", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsWiperError", - "Vehicle.Body.Windshield.Rear.Wiping.System.IsWiping", - "Vehicle.Body.Windshield.Rear.Wiping.System.Mode", - "Vehicle.Body.Windshield.Rear.Wiping.System.TargetPosition", - "Vehicle.Body.Windshield.Rear.Wiping.WiperWear", - "Vehicle.Cabin.Convertible.Status", - "Vehicle.Cabin.Door.Row1.DriverSide.IsChildLockActive", - "Vehicle.Cabin.Door.Row1.DriverSide.IsLocked", - "Vehicle.Cabin.Door.Row1.DriverSide.IsOpen", - "Vehicle.Cabin.Door.Row1.DriverSide.Shade.Position", - "Vehicle.Cabin.Door.Row1.DriverSide.Shade.Switch", - "Vehicle.Cabin.Door.Row1.DriverSide.Window.IsOpen", - "Vehicle.Cabin.Door.Row1.DriverSide.Window.Position", - "Vehicle.Cabin.Door.Row1.DriverSide.Window.Switch", - "Vehicle.Cabin.Door.Row1.PassengerSide.IsChildLockActive", - "Vehicle.Cabin.Door.Row1.PassengerSide.IsLocked", - "Vehicle.Cabin.Door.Row1.PassengerSide.IsOpen", - "Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Position", - "Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Switch", - "Vehicle.Cabin.Door.Row1.PassengerSide.Window.IsOpen", - "Vehicle.Cabin.Door.Row1.PassengerSide.Window.Position", - "Vehicle.Cabin.Door.Row1.PassengerSide.Window.Switch", - "Vehicle.Cabin.Door.Row2.DriverSide.IsChildLockActive", - "Vehicle.Cabin.Door.Row2.DriverSide.IsLocked", - "Vehicle.Cabin.Door.Row2.DriverSide.IsOpen", - "Vehicle.Cabin.Door.Row2.DriverSide.Shade.Position", - "Vehicle.Cabin.Door.Row2.DriverSide.Shade.Switch", - "Vehicle.Cabin.Door.Row2.DriverSide.Window.IsOpen", - "Vehicle.Cabin.Door.Row2.DriverSide.Window.Position", - "Vehicle.Cabin.Door.Row2.DriverSide.Window.Switch", - "Vehicle.Cabin.Door.Row2.PassengerSide.IsChildLockActive", - "Vehicle.Cabin.Door.Row2.PassengerSide.IsLocked", - "Vehicle.Cabin.Door.Row2.PassengerSide.IsOpen", - "Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Position", - "Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Switch", - "Vehicle.Cabin.Door.Row2.PassengerSide.Window.IsOpen", - "Vehicle.Cabin.Door.Row2.PassengerSide.Window.Position", - "Vehicle.Cabin.Door.Row2.PassengerSide.Window.Switch", - "Vehicle.Cabin.DoorCount", - "Vehicle.Cabin.DriverPosition", - "Vehicle.Cabin.HVAC.AmbientAirTemperature", - "Vehicle.Cabin.HVAC.IsAirConditioningActive", - "Vehicle.Cabin.HVAC.IsFrontDefrosterActive", - "Vehicle.Cabin.HVAC.IsRearDefrosterActive", - "Vehicle.Cabin.HVAC.IsRecirculationActive", - "Vehicle.Cabin.HVAC.PowerOptimizeLevel", - "Vehicle.Cabin.HVAC.Station.Row1.Driver.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row1.Driver.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row1.Driver.Temperature", - "Vehicle.Cabin.HVAC.Station.Row1.Passenger.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row1.Passenger.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row1.Passenger.Temperature", - "Vehicle.Cabin.HVAC.Station.Row2.Driver.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row2.Driver.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row2.Driver.Temperature", - "Vehicle.Cabin.HVAC.Station.Row2.Passenger.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row2.Passenger.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row2.Passenger.Temperature", - "Vehicle.Cabin.HVAC.Station.Row3.Driver.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row3.Driver.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row3.Driver.Temperature", - "Vehicle.Cabin.HVAC.Station.Row3.Passenger.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row3.Passenger.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row3.Passenger.Temperature", - "Vehicle.Cabin.HVAC.Station.Row4.Driver.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row4.Driver.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row4.Driver.Temperature", - "Vehicle.Cabin.HVAC.Station.Row4.Passenger.AirDistribution", - "Vehicle.Cabin.HVAC.Station.Row4.Passenger.FanSpeed", - "Vehicle.Cabin.HVAC.Station.Row4.Passenger.Temperature", - "Vehicle.Cabin.Infotainment.HMI.Brightness", - "Vehicle.Cabin.Infotainment.HMI.CurrentLanguage", - "Vehicle.Cabin.Infotainment.HMI.DateFormat", - "Vehicle.Cabin.Infotainment.HMI.DayNightMode", - "Vehicle.Cabin.Infotainment.HMI.DisplayOffDuration", - "Vehicle.Cabin.Infotainment.HMI.DistanceUnit", - "Vehicle.Cabin.Infotainment.HMI.EVEconomyUnits", - "Vehicle.Cabin.Infotainment.HMI.FontSize", - "Vehicle.Cabin.Infotainment.HMI.FuelEconomyUnits", - "Vehicle.Cabin.Infotainment.HMI.FuelVolumeUnit", - "Vehicle.Cabin.Infotainment.HMI.IsScreenAlwaysOn", - "Vehicle.Cabin.Infotainment.HMI.LastActionTime", - "Vehicle.Cabin.Infotainment.HMI.TemperatureUnit", - "Vehicle.Cabin.Infotainment.HMI.TimeFormat", - "Vehicle.Cabin.Infotainment.HMI.TirePressureUnit", - "Vehicle.Cabin.Infotainment.Media.Action", - "Vehicle.Cabin.Infotainment.Media.DeclinedURI", - "Vehicle.Cabin.Infotainment.Media.Played.Album", - "Vehicle.Cabin.Infotainment.Media.Played.Artist", - "Vehicle.Cabin.Infotainment.Media.Played.PlaybackRate", - "Vehicle.Cabin.Infotainment.Media.Played.Source", - "Vehicle.Cabin.Infotainment.Media.Played.Track", - "Vehicle.Cabin.Infotainment.Media.Played.URI", - "Vehicle.Cabin.Infotainment.Media.SelectedURI", - "Vehicle.Cabin.Infotainment.Media.Volume", - "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Latitude", - "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Longitude", - "Vehicle.Cabin.Infotainment.Navigation.GuidanceVoice", - "Vehicle.Cabin.Infotainment.Navigation.Mute", - "Vehicle.Cabin.Infotainment.Navigation.Volume", - "Vehicle.Cabin.Infotainment.PowerOptimizeLevel", - "Vehicle.Cabin.Infotainment.SmartphoneProjection.Active", - "Vehicle.Cabin.Infotainment.SmartphoneProjection.Source", - "Vehicle.Cabin.Infotainment.SmartphoneProjection.SupportedMode", - "Vehicle.Cabin.IsWindowChildLockEngaged", - "Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.Color", - "Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.Intensity", - "Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.Color", - "Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.Intensity", - "Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.IsLightOn", - "Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.Color", - "Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.Intensity", - "Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.Color", - "Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.Intensity", - "Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.IsLightOn", - "Vehicle.Cabin.Light.InteractiveLightBar.Color", - "Vehicle.Cabin.Light.InteractiveLightBar.Effect", - "Vehicle.Cabin.Light.InteractiveLightBar.Intensity", - "Vehicle.Cabin.Light.InteractiveLightBar.IsLightOn", - "Vehicle.Cabin.Light.IsDomeOn", - "Vehicle.Cabin.Light.IsGloveBoxOn", - "Vehicle.Cabin.Light.PerceivedAmbientLight", - "Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.IsLightOn", - "Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.Color", - "Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.Intensity", - "Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.IsLightOn", - "Vehicle.Cabin.PowerOptimizeLevel", - "Vehicle.Cabin.RearShade.Position", - "Vehicle.Cabin.RearShade.Switch", - "Vehicle.Cabin.RearviewMirror.DimmingLevel", - "Vehicle.Cabin.Seat.Row1.DriverSide.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Recline", - "Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row1.DriverSide.Headrest.Angle", - "Vehicle.Cabin.Seat.Row1.DriverSide.Headrest.Height", - "Vehicle.Cabin.Seat.Row1.DriverSide.Heating", - "Vehicle.Cabin.Seat.Row1.DriverSide.Height", - "Vehicle.Cabin.Seat.Row1.DriverSide.IsBelted", - "Vehicle.Cabin.Seat.Row1.DriverSide.IsOccupied", - "Vehicle.Cabin.Seat.Row1.DriverSide.Massage", - "Vehicle.Cabin.Seat.Row1.DriverSide.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row1.DriverSide.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row1.DriverSide.Position", - "Vehicle.Cabin.Seat.Row1.DriverSide.Seating.Length", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.SideBolster.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.SideBolster.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.DriverSide.Tilt", - "Vehicle.Cabin.Seat.Row1.Middle.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row1.Middle.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row1.Middle.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row1.Middle.Backrest.Recline", - "Vehicle.Cabin.Seat.Row1.Middle.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row1.Middle.Headrest.Angle", - "Vehicle.Cabin.Seat.Row1.Middle.Headrest.Height", - "Vehicle.Cabin.Seat.Row1.Middle.Heating", - "Vehicle.Cabin.Seat.Row1.Middle.Height", - "Vehicle.Cabin.Seat.Row1.Middle.IsBelted", - "Vehicle.Cabin.Seat.Row1.Middle.IsOccupied", - "Vehicle.Cabin.Seat.Row1.Middle.Massage", - "Vehicle.Cabin.Seat.Row1.Middle.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row1.Middle.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row1.Middle.Position", - "Vehicle.Cabin.Seat.Row1.Middle.Seating.Length", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.SideBolster.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.SideBolster.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.Middle.Tilt", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Recline", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Headrest.Angle", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Headrest.Height", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Heating", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Height", - "Vehicle.Cabin.Seat.Row1.PassengerSide.IsBelted", - "Vehicle.Cabin.Seat.Row1.PassengerSide.IsOccupied", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Massage", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Position", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Seating.Length", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.SideBolster.", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.SideBolster.", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Tilt", - "Vehicle.Cabin.Seat.Row2.DriverSide.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Recline", - "Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row2.DriverSide.Headrest.Angle", - "Vehicle.Cabin.Seat.Row2.DriverSide.Headrest.Height", - "Vehicle.Cabin.Seat.Row2.DriverSide.Heating", - "Vehicle.Cabin.Seat.Row2.DriverSide.Height", - "Vehicle.Cabin.Seat.Row2.DriverSide.IsBelted", - "Vehicle.Cabin.Seat.Row2.DriverSide.IsOccupied", - "Vehicle.Cabin.Seat.Row2.DriverSide.Massage", - "Vehicle.Cabin.Seat.Row2.DriverSide.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row2.DriverSide.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row2.DriverSide.Position", - "Vehicle.Cabin.Seat.Row2.DriverSide.Seating.Length", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.SideBolster.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.SideBolster.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.DriverSide.Tilt", - "Vehicle.Cabin.Seat.Row2.Middle.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row2.Middle.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row2.Middle.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row2.Middle.Backrest.Recline", - "Vehicle.Cabin.Seat.Row2.Middle.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row2.Middle.Headrest.Angle", - "Vehicle.Cabin.Seat.Row2.Middle.Headrest.Height", - "Vehicle.Cabin.Seat.Row2.Middle.Heating", - "Vehicle.Cabin.Seat.Row2.Middle.Height", - "Vehicle.Cabin.Seat.Row2.Middle.IsBelted", - "Vehicle.Cabin.Seat.Row2.Middle.IsOccupied", - "Vehicle.Cabin.Seat.Row2.Middle.Massage", - "Vehicle.Cabin.Seat.Row2.Middle.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row2.Middle.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row2.Middle.Position", - "Vehicle.Cabin.Seat.Row2.Middle.Seating.Length", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.SideBolster.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.SideBolster.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.Middle.Tilt", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Airbag.IsDeployed", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Lumbar.Height", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Lumbar.Support", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Recline", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.SideBolster.Support", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Headrest.Angle", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Headrest.Height", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Heating", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Height", - "Vehicle.Cabin.Seat.Row2.PassengerSide.IsBelted", - "Vehicle.Cabin.Seat.Row2.PassengerSide.IsOccupied", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Massage", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Occupant.Identifier.Issuer", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Occupant.Identifier.Subject", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Position", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Seating.Length", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.IsReclineBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.IsReclineForwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsLessSupportEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.SideBolster.", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.SideBolster.", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsCoolerEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsDownEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsTiltBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsTiltForwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsUpEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsWarmerEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Massage.IsDecreaseEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Massage.IsIncreaseEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Seating.IsBackwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Seating.IsForwardEngaged", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Tilt", - "Vehicle.Cabin.SeatPosCount", - "Vehicle.Cabin.SeatRowCount", - "Vehicle.Cabin.Sunroof.Position", - "Vehicle.Cabin.Sunroof.Shade.Position", - "Vehicle.Cabin.Sunroof.Shade.Switch", - "Vehicle.Cabin.Sunroof.Switch", - "Vehicle.CargoVolume", - "Vehicle.Chassis.Accelerator.PedalPosition", - "Vehicle.Chassis.Axle.Row1.AxleWidth", - "Vehicle.Chassis.Axle.Row1.SteeringAngle", - "Vehicle.Chassis.Axle.Row1.TireAspectRatio", - "Vehicle.Chassis.Axle.Row1.TireDiameter", - "Vehicle.Chassis.Axle.Row1.TireWidth", - "Vehicle.Chassis.Axle.Row1.TrackWidth", - "Vehicle.Chassis.Axle.Row1.TreadWidth", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.FluidLevel", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.IsBrakesWorn", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.IsFluidLevelLow", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.PadWear", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Speed", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.IsPressureLow", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure", - "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Temperature", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.FluidLevel", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.IsBrakesWorn", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.IsFluidLevelLow", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.PadWear", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Speed", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.IsPressureLow", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure", - "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Temperature", - "Vehicle.Chassis.Axle.Row1.WheelCount", - "Vehicle.Chassis.Axle.Row1.WheelDiameter", - "Vehicle.Chassis.Axle.Row1.WheelWidth", - "Vehicle.Chassis.Axle.Row2.AxleWidth", - "Vehicle.Chassis.Axle.Row2.SteeringAngle", - "Vehicle.Chassis.Axle.Row2.TireAspectRatio", - "Vehicle.Chassis.Axle.Row2.TireDiameter", - "Vehicle.Chassis.Axle.Row2.TireWidth", - "Vehicle.Chassis.Axle.Row2.TrackWidth", - "Vehicle.Chassis.Axle.Row2.TreadWidth", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.FluidLevel", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.IsBrakesWorn", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.IsFluidLevelLow", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.PadWear", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Speed", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.IsPressureLow", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure", - "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Temperature", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.FluidLevel", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.IsBrakesWorn", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.IsFluidLevelLow", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.PadWear", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Speed", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.IsPressureLow", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure", - "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Temperature", - "Vehicle.Chassis.Axle.Row2.WheelCount", - "Vehicle.Chassis.Axle.Row2.WheelDiameter", - "Vehicle.Chassis.Axle.Row2.WheelWidth", - "Vehicle.Chassis.AxleCount", - "Vehicle.Chassis.Brake.IsDriverEmergencyBrakingDetected", - "Vehicle.Chassis.Brake.PedalPosition", - "Vehicle.Chassis.ParkingBrake.IsAutoApplyEnabled", - "Vehicle.Chassis.ParkingBrake.IsEngaged", - "Vehicle.Chassis.SteeringWheel.Angle", - "Vehicle.Chassis.SteeringWheel.Extension", - "Vehicle.Chassis.SteeringWheel.Tilt", - "Vehicle.Chassis.Wheelbase", - "Vehicle.Connectivity.IsConnectivityAvailable", - "Vehicle.CurbWeight", - "Vehicle.CurrentLocation.Altitude", - "Vehicle.CurrentLocation.GNSSReceiver.FixType", - "Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.X", - "Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.Y", - "Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.Z", - "Vehicle.CurrentLocation.Heading", - "Vehicle.CurrentLocation.HorizontalAccuracy", - "Vehicle.CurrentLocation.Latitude", - "Vehicle.CurrentLocation.Longitude", - "Vehicle.CurrentLocation.Timestamp", - "Vehicle.CurrentLocation.VerticalAccuracy", - "Vehicle.CurrentOverallWeight", - "Vehicle.Driver.AttentiveProbability", - "Vehicle.Driver.DistractionLevel", - "Vehicle.Driver.FatigueLevel", - "Vehicle.Driver.HeartRate", - "Vehicle.Driver.Identifier.Issuer", - "Vehicle.Driver.Identifier.Subject", - "Vehicle.Driver.IsEyesOnRoad", - "Vehicle.Driver.IsHandsOnWheel", - "Vehicle.EmissionsCO2", - "Vehicle.Exterior.AirTemperature", - "Vehicle.Exterior.Humidity", - "Vehicle.Exterior.LightIntensity", - "Vehicle.GrossWeight", - "Vehicle.Height", - "Vehicle.IsBrokenDown", - "Vehicle.IsMoving", - "Vehicle.Length", - "Vehicle.LowVoltageBattery.CurrentCurrent", - "Vehicle.LowVoltageBattery.CurrentVoltage", - "Vehicle.LowVoltageBattery.NominalCapacity", - "Vehicle.LowVoltageBattery.NominalVoltage", - "Vehicle.LowVoltageSystemState", - "Vehicle.MaxTowBallWeight", - "Vehicle.MaxTowWeight", - "Vehicle.OBD.AbsoluteLoad", - "Vehicle.OBD.AcceleratorPositionD", - "Vehicle.OBD.AcceleratorPositionE", - "Vehicle.OBD.AcceleratorPositionF", - "Vehicle.OBD.AirStatus", - "Vehicle.OBD.AmbientAirTemperature", - "Vehicle.OBD.BarometricPressure", - "Vehicle.OBD.Catalyst.Bank1.Temperature1", - "Vehicle.OBD.Catalyst.Bank1.Temperature2", - "Vehicle.OBD.Catalyst.Bank2.Temperature1", - "Vehicle.OBD.Catalyst.Bank2.Temperature2", - "Vehicle.OBD.CommandedEGR", - "Vehicle.OBD.CommandedEVAP", - "Vehicle.OBD.CommandedEquivalenceRatio", - "Vehicle.OBD.ControlModuleVoltage", - "Vehicle.OBD.CoolantTemperature", - "Vehicle.OBD.DTCList", - "Vehicle.OBD.DistanceSinceDTCClear", - "Vehicle.OBD.DistanceWithMIL", - "Vehicle.OBD.DriveCycleStatus.DTCCount", - "Vehicle.OBD.DriveCycleStatus.IgnitionType", - "Vehicle.OBD.DriveCycleStatus.IsMILOn", - "Vehicle.OBD.EGRError", - "Vehicle.OBD.EVAPVaporPressure", - "Vehicle.OBD.EVAPVaporPressureAbsolute", - "Vehicle.OBD.EVAPVaporPressureAlternate", - "Vehicle.OBD.EngineLoad", - "Vehicle.OBD.EngineSpeed", - "Vehicle.OBD.EthanolPercent", - "Vehicle.OBD.FreezeDTC", - "Vehicle.OBD.FuelInjectionTiming", - "Vehicle.OBD.FuelLevel", - "Vehicle.OBD.FuelPressure", - "Vehicle.OBD.FuelRailPressureAbsolute", - "Vehicle.OBD.FuelRailPressureDirect", - "Vehicle.OBD.FuelRailPressureVac", - "Vehicle.OBD.FuelRate", - "Vehicle.OBD.FuelStatus", - "Vehicle.OBD.FuelType", - "Vehicle.OBD.HybridBatteryRemaining", - "Vehicle.OBD.IntakeTemp", - "Vehicle.OBD.IsPTOActive", - "Vehicle.OBD.LongTermFuelTrim1", - "Vehicle.OBD.LongTermFuelTrim2", - "Vehicle.OBD.LongTermO2Trim1", - "Vehicle.OBD.LongTermO2Trim2", - "Vehicle.OBD.LongTermO2Trim3", - "Vehicle.OBD.LongTermO2Trim4", - "Vehicle.OBD.MAF", - "Vehicle.OBD.MAP", - "Vehicle.OBD.MaxMAF", - "Vehicle.OBD.O2.Sensor1.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor1.Voltage", - "Vehicle.OBD.O2.Sensor2.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor2.Voltage", - "Vehicle.OBD.O2.Sensor3.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor3.Voltage", - "Vehicle.OBD.O2.Sensor4.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor4.Voltage", - "Vehicle.OBD.O2.Sensor5.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor5.Voltage", - "Vehicle.OBD.O2.Sensor6.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor6.Voltage", - "Vehicle.OBD.O2.Sensor7.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor7.Voltage", - "Vehicle.OBD.O2.Sensor8.ShortTermFuelTrim", - "Vehicle.OBD.O2.Sensor8.Voltage", - "Vehicle.OBD.O2WR.Sensor1.Current", - "Vehicle.OBD.O2WR.Sensor1.Lambda", - "Vehicle.OBD.O2WR.Sensor1.Voltage", - "Vehicle.OBD.O2WR.Sensor2.Current", - "Vehicle.OBD.O2WR.Sensor2.Lambda", - "Vehicle.OBD.O2WR.Sensor2.Voltage", - "Vehicle.OBD.O2WR.Sensor3.Current", - "Vehicle.OBD.O2WR.Sensor3.Lambda", - "Vehicle.OBD.O2WR.Sensor3.Voltage", - "Vehicle.OBD.O2WR.Sensor4.Current", - "Vehicle.OBD.O2WR.Sensor4.Lambda", - "Vehicle.OBD.O2WR.Sensor4.Voltage", - "Vehicle.OBD.O2WR.Sensor5.Current", - "Vehicle.OBD.O2WR.Sensor5.Lambda", - "Vehicle.OBD.O2WR.Sensor5.Voltage", - "Vehicle.OBD.O2WR.Sensor6.Current", - "Vehicle.OBD.O2WR.Sensor6.Lambda", - "Vehicle.OBD.O2WR.Sensor6.Voltage", - "Vehicle.OBD.O2WR.Sensor7.Current", - "Vehicle.OBD.O2WR.Sensor7.Lambda", - "Vehicle.OBD.O2WR.Sensor7.Voltage", - "Vehicle.OBD.O2WR.Sensor8.Current", - "Vehicle.OBD.O2WR.Sensor8.Lambda", - "Vehicle.OBD.O2WR.Sensor8.Voltage", - "Vehicle.OBD.OBDStandards", - "Vehicle.OBD.OilTemperature", - "Vehicle.OBD.OxygenSensorsIn2Banks", - "Vehicle.OBD.OxygenSensorsIn4Banks", - "Vehicle.OBD.PidsA", - "Vehicle.OBD.PidsB", - "Vehicle.OBD.PidsC", - "Vehicle.OBD.RelativeAcceleratorPosition", - "Vehicle.OBD.RelativeThrottlePosition", - "Vehicle.OBD.RunTime", - "Vehicle.OBD.RunTimeMIL", - "Vehicle.OBD.ShortTermFuelTrim1", - "Vehicle.OBD.ShortTermFuelTrim2", - "Vehicle.OBD.ShortTermO2Trim1", - "Vehicle.OBD.ShortTermO2Trim2", - "Vehicle.OBD.ShortTermO2Trim3", - "Vehicle.OBD.ShortTermO2Trim4", - "Vehicle.OBD.Speed", - "Vehicle.OBD.Status.DTCCount", - "Vehicle.OBD.Status.IgnitionType", - "Vehicle.OBD.Status.IsMILOn", - "Vehicle.OBD.ThrottleActuator", - "Vehicle.OBD.ThrottlePosition", - "Vehicle.OBD.ThrottlePositionB", - "Vehicle.OBD.ThrottlePositionC", - "Vehicle.OBD.TimeSinceDTCCleared", - "Vehicle.OBD.TimingAdvance", - "Vehicle.OBD.WarmupsSinceDTCClear", - "Vehicle.PowerOptimizeLevel", - "Vehicle.Powertrain.AccumulatedBrakingEnergy", - "Vehicle.Powertrain.CombustionEngine.AspirationType", - "Vehicle.Powertrain.CombustionEngine.Bore", - "Vehicle.Powertrain.CombustionEngine.CompressionRatio", - "Vehicle.Powertrain.CombustionEngine.Configuration", - "Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Capacity", - "Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.IsLevelLow", - "Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Level", - "Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Range", - "Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.DeltaPressure", - "Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.InletTemperature", - "Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.OutletTemperature", - "Vehicle.Powertrain.CombustionEngine.Displacement", - "Vehicle.Powertrain.CombustionEngine.ECT", - "Vehicle.Powertrain.CombustionEngine.EOP", - "Vehicle.Powertrain.CombustionEngine.EOT", - "Vehicle.Powertrain.CombustionEngine.EngineCode", - "Vehicle.Powertrain.CombustionEngine.EngineCoolantCapacity", - "Vehicle.Powertrain.CombustionEngine.EngineHours", - "Vehicle.Powertrain.CombustionEngine.EngineOilCapacity", - "Vehicle.Powertrain.CombustionEngine.EngineOilLevel", - "Vehicle.Powertrain.CombustionEngine.IdleHours", - "Vehicle.Powertrain.CombustionEngine.IsRunning", - "Vehicle.Powertrain.CombustionEngine.MAF", - "Vehicle.Powertrain.CombustionEngine.MAP", - "Vehicle.Powertrain.CombustionEngine.MaxPower", - "Vehicle.Powertrain.CombustionEngine.MaxTorque", - "Vehicle.Powertrain.CombustionEngine.NumberOfCylinders", - "Vehicle.Powertrain.CombustionEngine.NumberOfValvesPerCylinder", - "Vehicle.Powertrain.CombustionEngine.OilLifeRemaining", - "Vehicle.Powertrain.CombustionEngine.Power", - "Vehicle.Powertrain.CombustionEngine.Speed", - "Vehicle.Powertrain.CombustionEngine.StrokeLength", - "Vehicle.Powertrain.CombustionEngine.TPS", - "Vehicle.Powertrain.CombustionEngine.Torque", - "Vehicle.Powertrain.ElectricMotor.CoolantTemperature", - "Vehicle.Powertrain.ElectricMotor.EngineCode", - "Vehicle.Powertrain.ElectricMotor.MaxPower", - "Vehicle.Powertrain.ElectricMotor.MaxRegenPower", - "Vehicle.Powertrain.ElectricMotor.MaxRegenTorque", - "Vehicle.Powertrain.ElectricMotor.MaxTorque", - "Vehicle.Powertrain.ElectricMotor.Power", - "Vehicle.Powertrain.ElectricMotor.Speed", - "Vehicle.Powertrain.ElectricMotor.Temperature", - "Vehicle.Powertrain.ElectricMotor.Torque", - "Vehicle.Powertrain.FuelSystem.AbsoluteLevel", - "Vehicle.Powertrain.FuelSystem.AverageConsumption", - "Vehicle.Powertrain.FuelSystem.ConsumptionSinceStart", - "Vehicle.Powertrain.FuelSystem.HybridType", - "Vehicle.Powertrain.FuelSystem.InstantConsumption", - "Vehicle.Powertrain.FuelSystem.IsEngineStopStartEnabled", - "Vehicle.Powertrain.FuelSystem.IsFuelLevelLow", - "Vehicle.Powertrain.FuelSystem.Range", - "Vehicle.Powertrain.FuelSystem.RelativeLevel", - "Vehicle.Powertrain.FuelSystem.SupportedFuel", - "Vehicle.Powertrain.FuelSystem.SupportedFuelTypes", - "Vehicle.Powertrain.FuelSystem.TankCapacity", - "Vehicle.Powertrain.PowerOptimizeLevel", - "Vehicle.Powertrain.Range", - "Vehicle.Powertrain.TractionBattery.AccumulatedChargedEnergy", - "Vehicle.Powertrain.TractionBattery.AccumulatedChargedThroughput", - "Vehicle.Powertrain.TractionBattery.AccumulatedConsumedEnergy", - "Vehicle.Powertrain.TractionBattery.AccumulatedConsumedThroughput", - "Vehicle.Powertrain.TractionBattery.CellVoltage.Max", - "Vehicle.Powertrain.TractionBattery.CellVoltage.Min", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.DC", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase1", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase2", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase3", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeLimit", - "Vehicle.Powertrain.TractionBattery.Charging.ChargePlugType", - "Vehicle.Powertrain.TractionBattery.Charging.ChargePortFlap", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeRate", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.DC", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase1", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase2", - "Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase3", - "Vehicle.Powertrain.TractionBattery.Charging.IsCharging", - "Vehicle.Powertrain.TractionBattery.Charging.IsChargingCableConnected", - "Vehicle.Powertrain.TractionBattery.Charging.IsChargingCableLocked", - "Vehicle.Powertrain.TractionBattery.Charging.IsDischarging", - "Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.DC", - "Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase1", - "Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase2", - "Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase3", - "Vehicle.Powertrain.TractionBattery.Charging.Mode", - "Vehicle.Powertrain.TractionBattery.Charging.PowerLoss", - "Vehicle.Powertrain.TractionBattery.Charging.StartStopCharging", - "Vehicle.Powertrain.TractionBattery.Charging.Temperature", - "Vehicle.Powertrain.TractionBattery.Charging.TimeToComplete", - "Vehicle.Powertrain.TractionBattery.Charging.Timer.Mode", - "Vehicle.Powertrain.TractionBattery.Charging.Timer.Time", - "Vehicle.Powertrain.TractionBattery.CurrentCurrent", - "Vehicle.Powertrain.TractionBattery.CurrentPower", - "Vehicle.Powertrain.TractionBattery.CurrentVoltage", - "Vehicle.Powertrain.TractionBattery.DCDC.PowerLoss", - "Vehicle.Powertrain.TractionBattery.DCDC.Temperature", - "Vehicle.Powertrain.TractionBattery.GrossCapacity", - "Vehicle.Powertrain.TractionBattery.Id", - "Vehicle.Powertrain.TractionBattery.IsGroundConnected", - "Vehicle.Powertrain.TractionBattery.IsPowerConnected", - "Vehicle.Powertrain.TractionBattery.MaxVoltage", - "Vehicle.Powertrain.TractionBattery.NetCapacity", - "Vehicle.Powertrain.TractionBattery.NominalVoltage", - "Vehicle.Powertrain.TractionBattery.PowerLoss", - "Vehicle.Powertrain.TractionBattery.ProductionDate", - "Vehicle.Powertrain.TractionBattery.Range", - "Vehicle.Powertrain.TractionBattery.StateOfCharge.Current", - "Vehicle.Powertrain.TractionBattery.StateOfCharge.CurrentEnergy", - "Vehicle.Powertrain.TractionBattery.StateOfCharge.Displayed", - "Vehicle.Powertrain.TractionBattery.StateOfHealth", - "Vehicle.Powertrain.TractionBattery.Temperature.Average", - "Vehicle.Powertrain.TractionBattery.Temperature.Max", - "Vehicle.Powertrain.TractionBattery.Temperature.Min", - "Vehicle.Powertrain.Transmission.ClutchEngagement", - "Vehicle.Powertrain.Transmission.ClutchWear", - "Vehicle.Powertrain.Transmission.CurrentGear", - "Vehicle.Powertrain.Transmission.DiffLockFrontEngagement", - "Vehicle.Powertrain.Transmission.DiffLockRearEngagement", - "Vehicle.Powertrain.Transmission.DriveType", - "Vehicle.Powertrain.Transmission.GearChangeMode", - "Vehicle.Powertrain.Transmission.GearCount", - "Vehicle.Powertrain.Transmission.IsElectricalPowertrainEngaged", - "Vehicle.Powertrain.Transmission.IsLowRangeEngaged", - "Vehicle.Powertrain.Transmission.IsParkLockEngaged", - "Vehicle.Powertrain.Transmission.PerformanceMode", - "Vehicle.Powertrain.Transmission.SelectedGear", - "Vehicle.Powertrain.Transmission.Temperature", - "Vehicle.Powertrain.Transmission.TorqueDistribution", - "Vehicle.Powertrain.Transmission.TravelledDistance", - "Vehicle.Powertrain.Transmission.Type", - "Vehicle.Powertrain.Type", - "Vehicle.RoofLoad", - "Vehicle.Service.DistanceToService", - "Vehicle.Service.IsServiceDue", - "Vehicle.Service.TimeToService", - "Vehicle.Speed", - "Vehicle.StartTime", - "Vehicle.Trailer.IsConnected", - "Vehicle.TraveledDistance", - "Vehicle.TraveledDistanceSinceStart", - "Vehicle.TripDuration", - "Vehicle.TripMeterReading", - "Vehicle.VehicleIdentification.AcrissCode", - "Vehicle.VehicleIdentification.BodyType", - "Vehicle.VehicleIdentification.Brand", - "Vehicle.VehicleIdentification.DateVehicleFirstRegistered", - "Vehicle.VehicleIdentification.KnownVehicleDamages", - "Vehicle.VehicleIdentification.MeetsEmissionStandard", - "Vehicle.VehicleIdentification.Model", - "Vehicle.VehicleIdentification.OptionalExtras", - "Vehicle.VehicleIdentification.ProductionDate", - "Vehicle.VehicleIdentification.PurchaseDate", - "Vehicle.VehicleIdentification.VIN", - "Vehicle.VehicleIdentification.VehicleConfiguration", - "Vehicle.VehicleIdentification.VehicleInteriorColor", - "Vehicle.VehicleIdentification.VehicleInteriorType", - "Vehicle.VehicleIdentification.VehicleModelDate", - "Vehicle.VehicleIdentification.VehicleSeatingCapacity", - "Vehicle.VehicleIdentification.VehicleSpecialUsage", - "Vehicle.VehicleIdentification.WMI", - "Vehicle.VehicleIdentification.Year", - "Vehicle.VersionVSS.Label", - "Vehicle.VersionVSS.Major", - "Vehicle.VersionVSS.Minor", - "Vehicle.VersionVSS.Patch", - "Vehicle.Width", - ]; - - struct TestSignals<'a> { - glob: &'a TestGlob<'a>, - signals: &'a [&'a str], - } - - struct TestGlob<'a> { - raw: &'a str, - re: regex::Regex, - } - - impl<'a> TestSignals<'a> { - fn new(glob: &'a TestGlob, signals: &'a [&str]) -> Self { - Self { glob, signals } - } - - fn should_match_signals(&self, signals: &[&str]) -> bool { - let mut should_have_matched = Vec::new(); - let mut should_not_have_matched = Vec::new(); - for signal in self.signals { - if signals.contains(signal) { - if !self.glob.is_match(signal) { - should_have_matched.push(signal); - } - } else if self.glob.is_match(signal) { - should_not_have_matched.push(signal); - } - } - - for signal in &should_have_matched { - println!( - "glob '{}' should have matched signal '{}' but didn't", - self.glob.raw, signal - ); - } - - for signal in &should_not_have_matched { - println!( - "glob '{}' should not match signal '{}' but did", - self.glob.raw, signal - ); - } - - if !should_not_have_matched.is_empty() || !should_have_matched.is_empty() { - println!( - "glob '{}' (represented by regex: '{}') did not match the expected signals", - self.glob.raw, - self.glob.re.as_str() - ); - false - } else { - true - } - } - - fn should_match_signal(&self, signal: &str) -> bool { - self.should_match_signals(&[signal]) - } - - fn should_match_no_signals(&self) -> bool { - self.should_match_signals(&[]) - } - } - - impl<'a> TestGlob<'a> { - fn new(glob: &'a str) -> Self { - Self { - raw: glob, - re: to_regex(glob).unwrap(), - } - } - - fn with_signals(&self, signals: &'a [&str]) -> TestSignals { - TestSignals::new(self, signals) - } - - fn is_match(&self, haystack: &str) -> bool { - self.re.is_match(haystack) - } - - fn should_equal_regex_pattern(&self, regex_pattern: &str) -> bool { - if self.re.as_str() != regex_pattern { - println!( - "glob '{}' should translate to regex pattern '{}': instead got '{}'", - self.raw, - regex_pattern, - self.re.as_str() - ); - false - } else { - true - } - } - } - - fn using_glob(glob: &str) -> TestGlob { - TestGlob::new(glob) - } - - #[test] - fn test_matches_empty_glob() { - assert!(using_glob("") - .with_signals(ALL_SIGNALS) - .should_match_signals(ALL_SIGNALS)); - } - - #[test] - fn test_matches_only_multi_level_wildcard() { - assert!(using_glob("**") - .with_signals(ALL_SIGNALS) - .should_match_signals(ALL_SIGNALS)); - } - - #[test] - fn test_matches_only_single_level_wildcard() { - assert!(using_glob("*") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - } - - #[test] - fn test_matches_only_two_single_level_wildcard() { - assert!(using_glob("*.*") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.AverageSpeed", - "Vehicle.CargoVolume", - "Vehicle.CurbWeight", - "Vehicle.CurrentOverallWeight", - "Vehicle.EmissionsCO2", - "Vehicle.GrossWeight", - "Vehicle.Height", - "Vehicle.IsBrokenDown", - "Vehicle.IsMoving", - "Vehicle.Length", - "Vehicle.LowVoltageSystemState", - "Vehicle.MaxTowBallWeight", - "Vehicle.MaxTowWeight", - "Vehicle.PowerOptimizeLevel", - "Vehicle.RoofLoad", - "Vehicle.Speed", - "Vehicle.StartTime", - "Vehicle.TraveledDistance", - "Vehicle.TraveledDistanceSinceStart", - "Vehicle.TripDuration", - "Vehicle.TripMeterReading", - "Vehicle.Width", - ])); - } - - #[test] - fn test_matches_shared_prefix() { - assert!(using_glob("Vehicle.TraveledDistance") - .with_signals(ALL_SIGNALS) - .should_match_signal("Vehicle.TraveledDistance")); - } - - #[ignore] - #[test] - fn test_regex_single_subpath() { - assert!(using_glob("Vehicle").should_equal_regex_pattern("^Vehicle(?:\\..+)?$")); - } - - #[test] - fn test_matches_trailing_dot() { - assert!(using_glob("Vehicle.") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()) - } - - #[test] - fn test_matches_leading_dot() { - assert!(using_glob(".Speed") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()) - } - - #[test] - fn test_matches_single_subpath() { - assert!(using_glob("Vehic") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - assert!(using_glob("Vehicle") - .with_signals(ALL_SIGNALS) - .should_match_signals(ALL_SIGNALS)); - } - - #[ignore] - #[test] - fn test_regex_matches_multi_subpath() { - assert!(using_glob("Vehicle.Cabin.Sunroof") - .should_equal_regex_pattern(r"^Vehicle\.Cabin\.Sunroof(?:\..+)?$",)); - } - - #[test] - fn test_matches_something() { - assert!(using_glob("Vehicle.*.Weight") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - } - #[test] - fn test_matches_multi_subpath() { - using_glob("Vehicle.Cabin.Sunroof") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.Cabin.Sunroof.Position", - "Vehicle.Cabin.Sunroof.Shade.Position", - "Vehicle.Cabin.Sunroof.Shade.Switch", - "Vehicle.Cabin.Sunroof.Switch", - ]); - - // Make sure partial "last component" doesn't match - assert!(using_glob("Vehicle.Cabin.Sunroof") - .with_signals(&["Vehicle.Cabin.SunroofThing"]) - .should_match_no_signals()); - } - - #[test] - fn test_matches_full_path_of_signal() { - // Make sure it matches a full signal. - assert!(using_glob("Vehicle.Cabin.Sunroof.Shade.Position") - .with_signals(ALL_SIGNALS) - .should_match_signal("Vehicle.Cabin.Sunroof.Shade.Position")); - } - - #[ignore] - #[test] - fn test_regex_wildcard_at_end() { - assert!(using_glob("Vehicle.Cabin.Sunroof.*") - .should_equal_regex_pattern(r"^Vehicle\.Cabin\.Sunroof\.[^.\s\:]+$")); - } - - #[test] - fn test_matches_wildcard_at_end() { - assert!(using_glob("Vehicle.Cabin.Sunroof.*") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.Cabin.Sunroof.Position", - "Vehicle.Cabin.Sunroof.Switch", - ],)); - } - - #[ignore] - #[test] - fn test_regex_single_wildcard_in_middle() { - assert!(using_glob("Vehicle.Cabin.Sunroof.*.Position") - .should_equal_regex_pattern(r"^Vehicle\.Cabin\.Sunroof\.[^.\s\:]+\.Position$")); - } - - #[test] - fn test_matches_single_wildcard_in_middle() { - assert!(using_glob("Vehicle.Cabin.Sunroof.*.Position") - .with_signals(ALL_SIGNALS) - .should_match_signal("Vehicle.Cabin.Sunroof.Shade.Position")); - } - - #[test] - fn test_matches_multiple_single_wildcard_in_middle() { - assert!(using_glob("Vehicle.Cabin.*.*.Position") - .with_signals(ALL_SIGNALS) - .should_match_signals(&["Vehicle.Cabin.Sunroof.Shade.Position"])); - assert!(using_glob("Vehicle.*.Sunroof.*.Position") - .with_signals(ALL_SIGNALS) - .should_match_signals(&["Vehicle.Cabin.Sunroof.Shade.Position"])); - } - - #[test] - fn test_matches_combination_of_multiple_wildcard_and_single_wildcard() { - assert!(using_glob("**.*.*.*.Position") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Position", - "Vehicle.Cabin.Seat.Row2.PassengerSide.Position", - "Vehicle.Cabin.Seat.Row1.Middle.Position", - "Vehicle.Cabin.Door.Row2.DriverSide.Shade.Position", - "Vehicle.Cabin.Seat.Row1.PassengerSide.Position", - "Vehicle.Cabin.Door.Row1.DriverSide.Window.Position", - "Vehicle.Cabin.Door.Row1.DriverSide.Shade.Position", - "Vehicle.Cabin.Door.Row1.PassengerSide.Window.Position", - "Vehicle.Cabin.Door.Row2.DriverSide.Window.Position", - "Vehicle.Cabin.Door.Row2.PassengerSide.Window.Position", - "Vehicle.Cabin.Seat.Row2.Middle.Position", - "Vehicle.Cabin.Seat.Row1.DriverSide.Position", - "Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Position", - "Vehicle.Cabin.Seat.Row2.DriverSide.Position", - "Vehicle.Cabin.Sunroof.Shade.Position", - ])); - /* - It doesn't match for example: - "Vehicle.Cabin.RearShade.Position", - "Vehicle.Cabin.Sunroof.Position", - */ - } - - #[test] - fn test_matches_double_wildcard_and_multiple_single() { - assert!(using_glob("**.Door.*.*.Shade.Position") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.Cabin.Door.Row1.DriverSide.Shade.Position", - "Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Position", - "Vehicle.Cabin.Door.Row2.DriverSide.Shade.Position", - "Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Position", - ])); - } - - #[test] - fn test_matches_double_wildcard_in_middle() { - assert!(using_glob("Vehicle.Cabin.Sunroof.**.Position") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle.Cabin.Sunroof.Position", - "Vehicle.Cabin.Sunroof.Shade.Position", - ],)); - } - - #[ignore] - #[test] - fn test_regex_double_wildcard_at_beginning() { - assert!(using_glob("**.Sunroof").should_equal_regex_pattern(r"^.+\.Sunroof$")); - } - - #[test] - fn test_matches_double_wildcard_at_beginning() { - assert!(using_glob("**.Sunroof") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - - assert!(using_glob("**.Sunroof") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - } - - #[ignore] - #[test] - fn test_regex_single_wildcard_at_the_beginning() { - assert!(using_glob("*.Sunroof").should_equal_regex_pattern(r"^[^.\s\:]+\.Sunroof$")); - } - - #[test] - fn test_matches_single_wildcard_at_the_beginning() { - assert!(using_glob("*.Sunroof") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - } - - #[ignore] - #[test] - fn test_regex_single_non_matching_literal() { - assert!(using_glob("Sunroof").should_equal_regex_pattern(r"^Sunroof(?:\..+)?$")); - } - - #[test] - fn test_matches_single_non_matching_literal() { - assert!(using_glob("Sunroof") - .with_signals(ALL_SIGNALS) - .should_match_no_signals()); - } - - #[test] - fn test_matches_underscore_cases() { - assert!(using_glob("Vehicle._kuksa.**") - .with_signals(ALL_SIGNALS) - .should_match_signals(&[ - "Vehicle._kuksa.databroker.GitVersion", - "Vehicle._kuksa.databroker.CargoVersion", - "Vehicle._kuksa.databroker.GitVersion", - ],)); - } - - #[test] - fn test_is_valid_pattern() { - assert!(is_valid_pattern("String.*")); - assert!(is_valid_pattern("String.**")); - assert!(is_valid_pattern("Vehicle.Chassis.Axle.Row2.Wheel.*")); - assert!(is_valid_pattern("String.String.String.String.*")); - assert!(is_valid_pattern("String.String.String.String.**")); - assert!(is_valid_pattern("String.String.String.String.String.**")); - assert!(is_valid_pattern("String.String.String.*.String")); - assert!(is_valid_pattern("String.String.String.**.String")); - assert!(is_valid_pattern( - "String.String.String.String.String.**.String" - )); - assert!(is_valid_pattern( - "String.String.String.String.*.String.String" - )); - assert!(is_valid_pattern("String.*.String.String")); - assert!(is_valid_pattern("String.String.**.String.String")); - assert!(is_valid_pattern("String.**.String.String")); - assert!(is_valid_pattern("**.String.String.String.**")); - assert!(is_valid_pattern("**.String.String.9_tring.*")); - assert!(is_valid_pattern("**.string.String.String.*")); - assert!(is_valid_pattern("**._string.String.String.*")); - assert!(is_valid_pattern("String._kuksa.tring.9tring.*")); - assert!(is_valid_pattern("**.String")); - assert!(is_valid_pattern("*.String.String.String")); - assert!(is_valid_pattern("*.String")); - assert!(is_valid_pattern("*.String._")); - - assert!(!is_valid_pattern("String.*.String.String..")); - assert!(!is_valid_pattern("*.String.String.String..")); - assert!(!is_valid_pattern("String.**.St ring.String")); - assert!(!is_valid_pattern("String.**:String. String")); - assert!(!is_valid_pattern("String.**.St. .ring.String")); - assert!(!is_valid_pattern("String.**.St. : .ring.String")); - } - - #[test] - fn test_is_valid_path() { - assert!(is_valid_path("String.String.String.String")); - assert!(is_valid_path("String._kuksa.tring.9tring")); - - assert!(is_valid_path("Vehicle.Con_ñ_de_España,_sí")); - assert!(is_valid_path("Vehicle.Do_you_not_like_smörgåstårta")); - assert!(is_valid_path("Vehicle.tschö_mit_ö")); - assert!(is_valid_path("Vehicle.wie_heißt_das_lied")); - assert!(is_valid_path("Vehicle.東京_Москва_r#true")); - - assert!(!is_valid_path("String.String.String.")); - assert!(!is_valid_path("String.String.String.String..")); - assert!(!is_valid_path("String:String.String")); - assert!(!is_valid_path("String.St ring.String")); - assert!(!is_valid_path("String:String. String")); - assert!(!is_valid_path("String.St. .ring.String")); - assert!(!is_valid_path("String.St. : .ring.String")); - assert!(!is_valid_path("*.String:String. String")); - } - - #[test] - fn test_valid_regex_path() { - assert_eq!(to_regex_string("String.*"), "^String\\.[^.\\s\\:]+$"); - assert_eq!(to_regex_string("String.**"), "^String\\..*$"); - assert_eq!( - to_regex_string("String.String.String.String.*"), - "^String\\.String\\.String\\.String\\.[^.\\s\\:]+$" - ); - assert_eq!( - to_regex_string("String.String.String.String.**"), - "^String\\.String\\.String\\.String\\..*$" - ); - assert_eq!( - to_regex_string("String.String.String.String"), - "^String\\.String\\.String\\.String(?:\\..+)?$" - ); - assert_eq!( - to_regex_string("String.String.String.String.String.**"), - "^String\\.String\\.String\\.String\\.String\\..*$" - ); - assert_eq!( - to_regex_string("String.String.String.*.String"), - "^String\\.String\\.String\\.[^.\\s\\:]+\\.String$" - ); - assert_eq!( - to_regex_string("String.String.String.**.String"), - "^String\\.String\\.String[\\.[^.\\s\\:]+]*\\.String$" - ); - assert_eq!( - to_regex_string("String.String.String.String.String.**.String"), - "^String\\.String\\.String\\.String\\.String[\\.[^.\\s\\:]+]*\\.String$" - ); - assert_eq!( - to_regex_string("String.String.String.String.*.String.String"), - "^String\\.String\\.String\\.String\\.[^.\\s\\:]+\\.String\\.String$" - ); - assert_eq!( - to_regex_string("String.*.String.String"), - "^String\\.[^.\\s\\:]+\\.String\\.String$" - ); - assert_eq!( - to_regex_string("String.String.**.String.String"), - "^String\\.String[\\.[^.\\s\\:]+]*\\.String\\.String$" - ); - assert_eq!( - to_regex_string("String.**.String.String"), - "^String[\\.[^.\\s\\:]+]*\\.String\\.String$" - ); - assert_eq!( - to_regex_string("**.String.String.String.**"), - "^.+\\.String\\.String\\.String\\..*$" - ); - assert_eq!( - to_regex_string("**.String.String.String.*"), - "^.+\\.String\\.String\\.String\\.[^.\\s\\:]+$" - ); - assert_eq!(to_regex_string("**.String"), "^.+\\.String$"); - assert_eq!(to_regex_string("*.String"), "^[^.\\s\\:]+\\.String$"); - assert_eq!( - to_regex_string("*.String.String.String"), - "^[^.\\s\\:]+\\.String\\.String\\.String$" - ); - } -} diff --git a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/conversions.rs b/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/conversions.rs deleted file mode 100644 index d9b972d13..000000000 --- a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/conversions.rs +++ /dev/null @@ -1,340 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::kuksa::val::v1 as proto; - -use crate::broker; - -use std::convert::TryFrom; -use std::time::SystemTime; - -impl From<&broker::EntryType> for proto::EntryType { - fn from(from: &broker::EntryType) -> Self { - match from { - broker::EntryType::Sensor => proto::EntryType::Sensor, - broker::EntryType::Attribute => proto::EntryType::Attribute, - broker::EntryType::Actuator => proto::EntryType::Actuator, - } - } -} - -impl From for proto::DataType { - fn from(from: broker::DataType) -> Self { - match from { - broker::DataType::String => proto::DataType::String, - broker::DataType::Bool => proto::DataType::Boolean, - broker::DataType::Int8 => proto::DataType::Int8, - broker::DataType::Int16 => proto::DataType::Int16, - broker::DataType::Int32 => proto::DataType::Int32, - broker::DataType::Int64 => proto::DataType::Int64, - broker::DataType::Uint8 => proto::DataType::Uint8, - broker::DataType::Uint16 => proto::DataType::Uint16, - broker::DataType::Uint32 => proto::DataType::Uint32, - broker::DataType::Uint64 => proto::DataType::Uint64, - broker::DataType::Float => proto::DataType::Float, - broker::DataType::Double => proto::DataType::Double, - broker::DataType::StringArray => proto::DataType::StringArray, - broker::DataType::BoolArray => proto::DataType::BooleanArray, - broker::DataType::Int8Array => proto::DataType::Int8Array, - broker::DataType::Int16Array => proto::DataType::Int16Array, - broker::DataType::Int32Array => proto::DataType::Int32Array, - broker::DataType::Int64Array => proto::DataType::Int64Array, - broker::DataType::Uint8Array => proto::DataType::Uint8Array, - broker::DataType::Uint16Array => proto::DataType::Uint16Array, - broker::DataType::Uint32Array => proto::DataType::Uint32Array, - broker::DataType::Uint64Array => proto::DataType::Uint64Array, - broker::DataType::FloatArray => proto::DataType::FloatArray, - broker::DataType::DoubleArray => proto::DataType::DoubleArray, - } - } -} - -impl From for Option { - fn from(from: broker::Datapoint) -> Self { - match from.value { - broker::DataValue::NotAvailable => None, - broker::DataValue::Bool(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Bool(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::String(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::String(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Int32(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int32(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Int64(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int64(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Uint32(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint32(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Uint64(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint64(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Float(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Float(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Double(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Double(value)), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::BoolArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::BoolArray(proto::BoolArray { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::StringArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::StringArray(proto::StringArray { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Int32Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int32Array(proto::Int32Array { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Int64Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int64Array(proto::Int64Array { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Uint32Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint32Array(proto::Uint32Array { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::Uint64Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint64Array(proto::Uint64Array { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::FloatArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::FloatArray(proto::FloatArray { - values, - })), - timestamp: Some(from.ts.into()), - }), - broker::DataValue::DoubleArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::DoubleArray(proto::DoubleArray { - values, - })), - timestamp: Some(from.ts.into()), - }), - } - } -} - -impl From for Option { - fn from(from: broker::DataValue) -> Self { - match from { - broker::DataValue::NotAvailable => None, - broker::DataValue::Bool(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Bool(value)), - timestamp: None, - }), - broker::DataValue::String(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::String(value)), - timestamp: None, - }), - broker::DataValue::Int32(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int32(value)), - timestamp: None, - }), - broker::DataValue::Int64(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int64(value)), - timestamp: None, - }), - broker::DataValue::Uint32(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint32(value)), - timestamp: None, - }), - broker::DataValue::Uint64(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint64(value)), - timestamp: None, - }), - broker::DataValue::Float(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Float(value)), - timestamp: None, - }), - broker::DataValue::Double(value) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Double(value)), - timestamp: None, - }), - broker::DataValue::BoolArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::BoolArray(proto::BoolArray { - values, - })), - timestamp: None, - }), - broker::DataValue::StringArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::StringArray(proto::StringArray { - values, - })), - timestamp: None, - }), - broker::DataValue::Int32Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int32Array(proto::Int32Array { - values, - })), - timestamp: None, - }), - broker::DataValue::Int64Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Int64Array(proto::Int64Array { - values, - })), - timestamp: None, - }), - broker::DataValue::Uint32Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint32Array(proto::Uint32Array { - values, - })), - timestamp: None, - }), - broker::DataValue::Uint64Array(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::Uint64Array(proto::Uint64Array { - values, - })), - timestamp: None, - }), - broker::DataValue::FloatArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::FloatArray(proto::FloatArray { - values, - })), - timestamp: None, - }), - broker::DataValue::DoubleArray(values) => Some(proto::Datapoint { - value: Some(proto::datapoint::Value::DoubleArray(proto::DoubleArray { - values, - })), - timestamp: None, - }), - } - } -} - -impl From> for broker::DataValue { - fn from(from: Option) -> Self { - match from { - Some(value) => match value { - proto::datapoint::Value::String(value) => broker::DataValue::String(value), - proto::datapoint::Value::Bool(value) => broker::DataValue::Bool(value), - proto::datapoint::Value::Int32(value) => broker::DataValue::Int32(value), - proto::datapoint::Value::Int64(value) => broker::DataValue::Int64(value), - proto::datapoint::Value::Uint32(value) => broker::DataValue::Uint32(value), - proto::datapoint::Value::Uint64(value) => broker::DataValue::Uint64(value), - proto::datapoint::Value::Float(value) => broker::DataValue::Float(value), - proto::datapoint::Value::Double(value) => broker::DataValue::Double(value), - proto::datapoint::Value::StringArray(array) => { - broker::DataValue::StringArray(array.values) - } - proto::datapoint::Value::BoolArray(array) => { - broker::DataValue::BoolArray(array.values) - } - proto::datapoint::Value::Int32Array(array) => { - broker::DataValue::Int32Array(array.values) - } - proto::datapoint::Value::Int64Array(array) => { - broker::DataValue::Int64Array(array.values) - } - proto::datapoint::Value::Uint32Array(array) => { - broker::DataValue::Uint32Array(array.values) - } - proto::datapoint::Value::Uint64Array(array) => { - broker::DataValue::Uint64Array(array.values) - } - proto::datapoint::Value::FloatArray(array) => { - broker::DataValue::FloatArray(array.values) - } - proto::datapoint::Value::DoubleArray(array) => { - broker::DataValue::DoubleArray(array.values) - } - }, - None => broker::DataValue::NotAvailable, - } - } -} - -impl From<&broker::Field> for proto::Field { - fn from(from: &broker::Field) -> Self { - match from { - broker::Field::Datapoint => proto::Field::Value, - broker::Field::ActuatorTarget => proto::Field::ActuatorTarget, - broker::Field::MetadataUnit => proto::Field::MetadataUnit, - } - } -} - -impl TryFrom<&proto::Field> for broker::Field { - type Error = &'static str; - - fn try_from(from: &proto::Field) -> Result { - match from { - proto::Field::Value => Ok(broker::Field::Datapoint), - proto::Field::ActuatorTarget => Ok(broker::Field::ActuatorTarget), - _ => Err("Unknown field"), - } - } -} - -impl From for broker::Datapoint { - fn from(from: proto::Datapoint) -> Self { - Self { - ts: SystemTime::now(), - source_ts: match from.timestamp { - Some(ts) => match std::convert::TryInto::try_into(ts) { - Ok(ts) => Some(ts), - Err(_) => None, - }, - None => None, - }, - value: broker::DataValue::from(from.value), - } - } -} - -impl From for proto::DataEntry { - fn from(from: broker::EntryUpdate) -> Self { - Self { - path: from.path.unwrap_or_default(), - value: match from.datapoint { - Some(datapoint) => Option::::from(datapoint), - None => None, - }, - actuator_target: match from.actuator_target { - Some(Some(actuator_target)) => Option::::from(actuator_target), - Some(None) => None, - None => None, - }, - metadata: { - let metadata = proto::Metadata { - unit: from.unit, - ..Default::default() - }; - Some(metadata) - }, - } - } -} diff --git a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/mod.rs b/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/mod.rs deleted file mode 100644 index 2da408827..000000000 --- a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -mod conversions; -mod val; diff --git a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs b/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs deleted file mode 100644 index 72a8fa87a..000000000 --- a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs +++ /dev/null @@ -1,746 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::collections::HashMap; -use std::collections::HashSet; -use std::iter::FromIterator; -use std::pin::Pin; - -use databroker_proto::kuksa::val::v1 as proto; -use databroker_proto::kuksa::val::v1::DataEntryError; -use tokio_stream::Stream; -use tokio_stream::StreamExt; -use tracing::debug; - -use crate::broker; -use crate::broker::EntryReadAccess; -use crate::broker::ReadError; -use crate::broker::SubscriptionError; -use crate::glob; -use crate::permissions::Permissions; - -#[tonic::async_trait] -impl proto::val_server::Val for broker::DataBroker { - async fn get( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - let requested = request.into_inner().entries; - if requested.is_empty() { - Err(tonic::Status::new( - tonic::Code::InvalidArgument, - "No datapoints requested".to_string(), - )) - } else { - let mut entries = Vec::new(); - let mut errors = Vec::new(); - /* - * valid_requests: A collection of valid requests, each represented as a tuple with five fields: - * - Regex: The regular expression created from the string path request. - * - Fields: A HashSet of proto::Field objects extracted from the request. - * - RequestPath: The original request path, used for error reporting when no entries match. - * - IsMatch: A boolean flag indicating whether the current request matches any entry. - * - Error: An optional ReadError representing a permission error that may occur when querying a valid path entry. - */ - let mut valid_requests: Vec<( - regex::Regex, - HashSet, - String, - bool, - Option, - )> = Vec::new(); - - // Fill valid_requests structure. - for request in requested { - if request.path.contains('*') && !glob::is_valid_pattern(&request.path) { - errors.push(proto::DataEntryError { - path: request.path, - error: Some(proto::Error { - code: 400, - reason: "bad_request".to_owned(), - message: "Bad Wildcard Pattern Request".to_owned(), - }), - }); - continue; - } - - let view = proto::View::from_i32(request.view).ok_or_else(|| { - tonic::Status::invalid_argument(format!("Invalid View (id: {}", request.view)) - })?; - let fields = HashSet::::from_iter(request.fields.iter().filter_map( - |id| proto::Field::from_i32(*id), // Ignore unknown fields for now - )); - let view_fields = combine_view_and_fields(view, fields); - debug!("Getting fields: {:?}", view_fields); - - let regex_exp = glob::to_regex(&request.path); - match regex_exp { - Ok(value) => { - valid_requests.push((value, view_fields, request.path, false, None)); - } - Err(_) => { - errors.push(proto::DataEntryError { - path: request.path, - error: Some(proto::Error { - code: 400, - reason: "bad regex".to_owned(), - message: "Regex can't be created for provided path".to_owned(), - }), - }); - } - } - } - if !valid_requests.is_empty() { - broker - .for_each_entry(|entry| { - let mut result_fields: HashSet = HashSet::new(); - for (regex, view_fields, _, is_match, op_error) in &mut valid_requests { - let path = &entry.metadata().path; - if regex.is_match(path) { - // Update the `is_match` to indicate a valid and used request path. - *is_match = true; - if view_fields.contains(&proto::Field::Metadata) { - result_fields.extend(view_fields.clone()); - } - if view_fields.contains(&proto::Field::ActuatorTarget) - || view_fields.contains(&proto::Field::Value) - { - match entry.datapoint() { - Ok(_) => { - // If the entry's path matches the regex and there is access permission, - // add the result fields to the current entry. - result_fields.extend(view_fields.clone()); - } - Err(error) => { - //Propagate the error - *op_error = Some(error); - } - } - } - } - } - - // If there are result fields, add them to the entries list. - if !result_fields.is_empty() { - let proto_entry = - proto_entry_from_entry_and_fields(entry, result_fields); - debug!("Getting datapoint: {:?}", proto_entry); - entries.push(proto_entry); - } - }) - .await; - } - - /* - * Handle Unmatched or Permission Errors - * - * After processing valid requests, this section iterates over the `valid_requests` vector - * to check if any requests didn't have matching entries or encountered permission errors. - * - * For each unmatched request, a "not_found" error message is added to the `errors` list. - * For requests with permission errors, a "forbidden" error message is added. - */ - for (_, _, path, is_match, error) in valid_requests { - if !is_match { - errors.push(proto::DataEntryError { - path: path.to_owned(), - error: Some(proto::Error { - code: 404, - reason: "not_found".to_owned(), - message: "No entries found for the provided path".to_owned(), - }), - }); - } else if let Some(_error) = error { - // clear the entries vector since we only want to return rerrors - // and not partial success - entries.clear(); - errors.push(proto::DataEntryError { - path: path.to_owned(), - error: Some(proto::Error { - code: 403, - reason: "forbidden".to_owned(), - message: "Permission denied for some entries".to_owned(), - }), - }); - } - } - - // Not sure how to handle the "global error". - // Fall back to just use the first path specific error if any - let error = match errors.first() { - Some(first) => first.error.clone(), - None => None, - }; - - let response = proto::GetResponse { - entries, - errors, - error, - }; - Ok(tonic::Response::new(response)) - } - } - - async fn set( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - - let broker = self.authorized_access(&permissions); - - // Collect errors encountered - let mut errors = Vec::::new(); - - let mut updates = Vec::<(i32, broker::EntryUpdate)>::new(); - for request in request.into_inner().updates { - match &request.entry { - Some(entry) => match broker.get_id_by_path(&entry.path).await { - Some(id) => { - let fields = - HashSet::::from_iter(request.fields.iter().filter_map( - |id| proto::Field::from_i32(*id), // Ignore unknown fields for now - )); - - if entry.actuator_target.is_some() { - if let Some(metadata) = broker.get_metadata(id).await { - if metadata.entry_type != broker::EntryType::Actuator { - return Err(tonic::Status::invalid_argument( - "Tried to set a target value for a non-actuator. Non-actuators have no target value.".to_string(), - )); - } - } - } - - let entry = match &request.entry { - Some(entry) => entry, - None => { - return Err(tonic::Status::invalid_argument( - "Empty entry".to_string(), - )) - } - }; - debug!("Settings fields: {:?}", fields); - let update = - broker::EntryUpdate::from_proto_entry_and_fields(entry, fields); - updates.push((id, update)); - } - None => { - let message = format!("{} not found", entry.path); - errors.push(proto::DataEntryError { - path: entry.path.clone(), - error: Some(proto::Error { - code: 404, - reason: "not_found".to_string(), - message, - }), - }) - } - }, - None => { - return Err(tonic::Status::invalid_argument( - "Path is required".to_string(), - )) - } - } - } - - match broker.update_entries(updates).await { - Ok(()) => {} - Err(err) => { - debug!("Failed to set datapoint: {:?}", err); - for (id, error) in err.into_iter() { - if let Some(metadata) = broker.get_metadata(id).await { - let path = metadata.path.clone(); - let data_entry_error = match error { - broker::UpdateError::NotFound => DataEntryError { - path: path.clone(), - error: Some(proto::Error { - code: 404, - reason: String::from("not found"), - message: format!("no datapoint registered for path {path}"), - }), - }, - broker::UpdateError::WrongType => DataEntryError { - path, - error: Some(proto::Error { - code: 400, - reason: String::from("type mismatch"), - message: - "cannot set existing datapoint to value of different type" - .to_string(), - }), - }, - broker::UpdateError::UnsupportedType => DataEntryError { - path, - error: Some(proto::Error { - code: 400, - reason: String::from("unsupported type"), - message: "cannot set datapoint to value of unsupported type" - .to_string(), - }), - }, - broker::UpdateError::OutOfBounds => DataEntryError { - path, - error: Some(proto::Error { - code: 400, - reason: String::from("value out of bounds"), - message: String::from("given value exceeds type's boundaries"), - }), - }, - broker::UpdateError::PermissionDenied => DataEntryError { - path: path.clone(), - error: Some(proto::Error { - code: 403, - reason: String::from("forbidden"), - message: format!("Access was denied for {path}"), - }), - }, - broker::UpdateError::PermissionExpired => DataEntryError { - path, - error: Some(proto::Error { - code: 401, - reason: String::from("unauthorized"), - message: String::from("Unauthorized"), - }), - }, - }; - errors.push(data_entry_error); - } - } - } - } - - Ok(tonic::Response::new(proto::SetResponse { - error: None, - errors, - })) - } - - type SubscribeStream = Pin< - Box< - dyn Stream> - + Send - + Sync - + 'static, - >, - >; - - async fn subscribe( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - let request = request.into_inner(); - - if request.entries.is_empty() { - return Err(tonic::Status::invalid_argument( - "Subscription request must contain at least one entry.", - )); - } - - let mut valid_requests: HashMap)> = - HashMap::new(); - - for entry in &request.entries { - if entry.path.contains('*') && !glob::is_valid_pattern(&entry.path) { - tonic::Status::new(tonic::Code::InvalidArgument, "Invalid Pattern Argument"); - continue; - } - - let regex_exp = glob::to_regex(&entry.path); - if let Ok(regex) = regex_exp { - let mut fields = HashSet::new(); - for id in &entry.fields { - if let Some(field) = proto::Field::from_i32(*id) { - match field { - proto::Field::Value => { - fields.insert(broker::Field::Datapoint); - } - proto::Field::ActuatorTarget => { - fields.insert(broker::Field::ActuatorTarget); - } - proto::Field::MetadataUnit => { - fields.insert(broker::Field::MetadataUnit); - } - _ => { - // Just ignore other fields for now - } - } - }; - } - valid_requests.insert(entry.path.clone(), (regex, fields)); - } - } - - let mut entries: HashMap> = HashMap::new(); - - if !valid_requests.is_empty() { - for (path, (regex, fields)) in valid_requests { - let mut requested_path_found = false; - let mut permission_error = false; - broker - .for_each_entry(|entry| { - let entry_path = &entry.metadata().path; - if regex.is_match(entry_path) { - requested_path_found = true; - entries - .entry(entry.metadata().id) - .and_modify(|existing_fields| { - existing_fields.extend(fields.clone()); - }) - .or_insert(fields.clone()); - - match entry.datapoint() { - Ok(_) => {} - Err(_) => permission_error = true, - } - } - }) - .await; - if !requested_path_found { - let message = format!("No entries found for the provided. Path: {}", path); - return Err(tonic::Status::new(tonic::Code::NotFound, message)); - } - if permission_error { - let message = format!("Permission denied for some entries. Path: {}", path); - return Err(tonic::Status::new(tonic::Code::PermissionDenied, message)); - } - } - } - - match broker.subscribe(entries).await { - Ok(stream) => { - let stream = convert_to_proto_stream(stream); - Ok(tonic::Response::new(Box::pin(stream))) - } - Err(SubscriptionError::NotFound) => { - Err(tonic::Status::new(tonic::Code::NotFound, "Path not found")) - } - Err(SubscriptionError::InvalidInput) => Err(tonic::Status::new( - tonic::Code::InvalidArgument, - "Invalid Argument", - )), - Err(SubscriptionError::InternalError) => { - Err(tonic::Status::new(tonic::Code::Internal, "Internal Error")) - } - } - } - - async fn get_server_info( - &self, - _request: tonic::Request, - ) -> Result, tonic::Status> { - let server_info = proto::GetServerInfoResponse { - name: "databroker".to_owned(), - version: self.get_version().to_owned(), - }; - Ok(tonic::Response::new(server_info)) - } -} - -fn convert_to_proto_stream( - input: impl Stream, -) -> impl Stream> { - input.map(move |item| { - let mut updates = Vec::new(); - for update in item.updates { - updates.push(proto::EntryUpdate { - entry: Some(proto::DataEntry::from(update.update)), - fields: update - .fields - .iter() - .map(|field| proto::Field::from(field) as i32) - .collect(), - }); - } - let response = proto::SubscribeResponse { updates }; - Ok(response) - }) -} - -fn proto_entry_from_entry_and_fields( - entry: EntryReadAccess, - fields: HashSet, -) -> proto::DataEntry { - let path = entry.metadata().path.to_string(); - let value = if fields.contains(&proto::Field::Value) { - match entry.datapoint() { - Ok(value) => Option::::from(value.clone()), - Err(_) => None, - } - } else { - None - }; - let actuator_target = if fields.contains(&proto::Field::ActuatorTarget) { - match entry.actuator_target() { - Ok(value) => match value { - Some(value) => Option::::from(value.clone()), - None => None, - }, - Err(_) => None, - } - } else { - None - }; - let metadata = { - let mut metadata = proto::Metadata::default(); - let mut metadata_is_set = false; - - let all = fields.contains(&proto::Field::Metadata); - - if all || fields.contains(&proto::Field::MetadataDataType) { - metadata_is_set = true; - metadata.data_type = proto::DataType::from(entry.metadata().data_type.clone()) as i32; - } - if all || fields.contains(&proto::Field::MetadataDescription) { - metadata_is_set = true; - metadata.description = Some(entry.metadata().description.clone()); - } - if all || fields.contains(&proto::Field::MetadataEntryType) { - metadata_is_set = true; - metadata.entry_type = proto::EntryType::from(&entry.metadata().entry_type) as i32; - } - if all || fields.contains(&proto::Field::MetadataComment) { - metadata_is_set = true; - // TODO: Add to Metadata - metadata.comment = None; - } - if all || fields.contains(&proto::Field::MetadataDeprecation) { - metadata_is_set = true; - // TODO: Add to Metadata - metadata.deprecation = None; - } - if all || fields.contains(&proto::Field::MetadataUnit) { - metadata_is_set = true; - metadata.unit = entry.metadata().unit.clone(); - } - if all || fields.contains(&proto::Field::MetadataValueRestriction) { - metadata_is_set = true; - // TODO: Add to Metadata - } - if all || fields.contains(&proto::Field::MetadataActuator) { - metadata_is_set = true; - // TODO: Add to Metadata - metadata.entry_specific = match entry.metadata().entry_type { - broker::EntryType::Actuator => { - // Some(proto::metadata::EntrySpecific::Actuator( - // proto::Actuator::default(), - // )); - None - } - broker::EntryType::Sensor | broker::EntryType::Attribute => None, - }; - } - if all || fields.contains(&proto::Field::MetadataSensor) { - metadata_is_set = true; - // TODO: Add to Metadata - metadata.entry_specific = match entry.metadata().entry_type { - broker::EntryType::Sensor => { - // Some(proto::metadata::EntrySpecific::Sensor( - // proto::Sensor::default(), - // )); - None - } - broker::EntryType::Attribute | broker::EntryType::Actuator => None, - }; - } - if all || fields.contains(&proto::Field::MetadataAttribute) { - metadata_is_set = true; - // TODO: Add to Metadata - metadata.entry_specific = match entry.metadata().entry_type { - broker::EntryType::Attribute => { - // Some(proto::metadata::EntrySpecific::Attribute( - // proto::Attribute::default(), - // )); - None - } - broker::EntryType::Sensor | broker::EntryType::Actuator => None, - }; - } - - if metadata_is_set { - Some(metadata) - } else { - None - } - }; - proto::DataEntry { - path, - value, - actuator_target, - metadata, - } -} - -fn combine_view_and_fields( - view: proto::View, - fields: impl IntoIterator, -) -> HashSet { - let mut combined = HashSet::new(); - - combined.extend(fields); - - match view { - proto::View::Unspecified => { - // If no fields are specified, View::Unspecified will - // default to the equivalent of View::CurrentValue - if combined.is_empty() { - combined.insert(proto::Field::Path); - combined.insert(proto::Field::Value); - } - } - proto::View::CurrentValue => { - combined.insert(proto::Field::Path); - combined.insert(proto::Field::Value); - } - proto::View::TargetValue => { - combined.insert(proto::Field::Path); - combined.insert(proto::Field::ActuatorTarget); - } - proto::View::Metadata => { - combined.insert(proto::Field::Path); - combined.insert(proto::Field::Metadata); - } - proto::View::Fields => {} - proto::View::All => { - combined.insert(proto::Field::Path); - combined.insert(proto::Field::Value); - combined.insert(proto::Field::ActuatorTarget); - combined.insert(proto::Field::Metadata); - } - } - - combined -} - -impl broker::EntryUpdate { - fn from_proto_entry_and_fields( - entry: &proto::DataEntry, - fields: HashSet, - ) -> Self { - let datapoint = if fields.contains(&proto::Field::Value) { - entry - .value - .as_ref() - .map(|value| broker::Datapoint::from(value.clone())) - } else { - None - }; - let actuator_target = if fields.contains(&proto::Field::ActuatorTarget) { - match &entry.actuator_target { - Some(datapoint) => Some(Some(broker::Datapoint::from(datapoint.clone()))), - None => Some(None), - } - } else { - None - }; - Self { - path: None, - datapoint, - actuator_target, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{broker::DataBroker, permissions}; - - #[tokio::test] - async fn test_update_datapoint_using_wrong_type() { - let broker = DataBroker::default(); - let authorized_access = broker.authorized_access(&permissions::ALLOW_ALL); - - authorized_access - .add_entry( - "test.datapoint1".to_owned(), - broker::DataType::Bool, - broker::ChangeType::OnChange, - broker::EntryType::Sensor, - "Test datapoint 1".to_owned(), - None, - None, - ) - .await - .expect("Register datapoint should succeed"); - - let mut req = tonic::Request::new(proto::SetRequest { - updates: vec![proto::EntryUpdate { - fields: vec![proto::Field::Value as i32], - entry: Some(proto::DataEntry { - path: "test.datapoint1".to_owned(), - value: Some(proto::Datapoint { - timestamp: Some(std::time::SystemTime::now().into()), - value: Some(proto::datapoint::Value::Int32(1456)), - }), - metadata: None, - actuator_target: None, - }), - }], - }); - - // Manually insert permissions - req.extensions_mut().insert(permissions::ALLOW_ALL.clone()); - - match proto::val_server::Val::set(&broker, req) - .await - .map(|res| res.into_inner()) - { - Ok(set_response) => { - assert!( - !set_response.errors.is_empty(), - "databroker should not allow updating boolean datapoint with an int32" - ); - let error = set_response.errors[0] - .to_owned() - .error - .expect("error details are missing"); - assert_eq!(error.code, 400, "unexpected error code"); - } - Err(_status) => panic!("failed to execute set request"), - } - } -} diff --git a/kuksa_databroker/databroker/src/grpc/mod.rs b/kuksa_databroker/databroker/src/grpc/mod.rs deleted file mode 100644 index c4c86d4ac..000000000 --- a/kuksa_databroker/databroker/src/grpc/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -pub mod server; - -mod kuksa_val_v1; -mod sdv_databroker_v1; diff --git a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs deleted file mode 100644 index 532ae1f10..000000000 --- a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs +++ /dev/null @@ -1,244 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use tonic::{Code, Request, Response, Status}; - -use databroker_proto::sdv::databroker::v1 as proto; - -use tokio_stream::{Stream, StreamExt}; - -use std::collections::HashMap; -use std::pin::Pin; - -use crate::broker::{self, ReadError}; -use crate::permissions::Permissions; - -use tracing::debug; - -#[tonic::async_trait] -impl proto::broker_server::Broker for broker::DataBroker { - async fn get_datapoints( - &self, - request: Request, - ) -> Result, Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - let requested = request.into_inner(); - if requested.datapoints.is_empty() { - Err(Status::new( - Code::InvalidArgument, - "No datapoints requested".to_string(), - )) - } else { - let mut datapoints = HashMap::new(); - - for name in requested.datapoints { - match broker.get_datapoint_by_path(&name).await { - Ok(datapoint) => { - datapoints.insert(name, proto::Datapoint::from(&datapoint)); - } - Err(err) => { - // Datapoint doesn't exist - datapoints.insert( - name, - proto::Datapoint { - timestamp: None, - value: match err { - ReadError::NotFound => { - Some(proto::datapoint::Value::FailureValue( - proto::datapoint::Failure::UnknownDatapoint.into(), - )) - } - ReadError::PermissionDenied | ReadError::PermissionExpired => { - Some(proto::datapoint::Value::FailureValue( - proto::datapoint::Failure::AccessDenied.into(), - )) - } - }, - }, - ); - } - } - } - - let reply = proto::GetDatapointsReply { datapoints }; - - Ok(Response::new(reply)) - } - } - - async fn set_datapoints( - &self, - request: tonic::Request, - ) -> Result, Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - // Collect errors encountered - let mut errors = HashMap::::new(); - let mut id_to_path = HashMap::::new(); // Map id to path for errors - let message = request.into_inner(); - - let ids = { - let mut ids = Vec::new(); - for (path, datapoint) in message.datapoints { - match broker.get_metadata_by_path(&path).await { - Some(metadata) => { - match metadata.entry_type { - broker::EntryType::Sensor | broker::EntryType::Attribute => { - // Cannot set sensor / attribute through the `Broker` API. - debug!("Cannot set sensor / attribute through the `Broker` API."); - errors.insert( - path.clone(), - proto::DatapointError::AccessDenied as i32, - ); - } - broker::EntryType::Actuator => { - ids.push(( - metadata.id, - broker::EntryUpdate { - path: None, - datapoint: None, - actuator_target: Some(Some(broker::Datapoint::from( - &datapoint, - ))), - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )); - } - } - id_to_path.insert(metadata.id, path); - } - None => { - errors.insert(path.clone(), proto::DatapointError::UnknownDatapoint as i32); - } - }; - } - ids - }; - - match broker.update_entries(ids).await { - Ok(()) => {} - Err(err) => { - debug!("Failed to set datapoint: {:?}", err); - errors.extend(err.iter().map(|(id, error)| { - ( - id_to_path[id].clone(), - proto::DatapointError::from(error) as i32, - ) - })) - } - } - - Ok(Response::new(proto::SetDatapointsReply { errors })) - } - - type SubscribeStream = - Pin> + Send + Sync + 'static>>; - - async fn subscribe( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - let query = request.into_inner().query; - match broker.subscribe_query(&query).await { - Ok(stream) => { - let stream = convert_to_proto_stream(stream); - debug!("Subscribed to new query"); - Ok(Response::new(Box::pin(stream))) - } - Err(e) => Err(Status::new(Code::InvalidArgument, format!("{e:?}"))), - } - } - - async fn get_metadata( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - - let broker = self.authorized_access(&permissions); - - let request = request.into_inner(); - - let list = if request.names.is_empty() { - broker - .map_entries(|entry| proto::Metadata::from(entry.metadata())) - .await - } else { - broker - .with_read_lock(|db| { - request - .names - .iter() - .filter_map(|name| db.get_metadata_by_path(name)) - .map(proto::Metadata::from) - .collect::>() - }) - .await - }; - let reply = proto::GetMetadataReply { list }; - Ok(Response::new(reply)) - } -} - -fn convert_to_proto_stream( - input: impl Stream, -) -> impl Stream> { - input.map(move |item| { - // debug!("item.id: {:?}", item.value); - let mut datapoints = HashMap::new(); - for field in item.fields { - let value = proto::Datapoint::from(&field); - datapoints.insert(field.name, value); - } - let notification = proto::SubscribeReply { fields: datapoints }; - Ok(notification) - }) -} diff --git a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/collector.rs b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/collector.rs deleted file mode 100644 index 048035f10..000000000 --- a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/collector.rs +++ /dev/null @@ -1,266 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::collections::HashMap; - -use databroker_proto::sdv::databroker::v1 as proto; - -use tokio::select; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{Code, Response, Status}; -use tracing::debug; - -use crate::{ - broker::{self, RegistrationError}, - permissions::Permissions, -}; - -#[tonic::async_trait] -impl proto::collector_server::Collector for broker::DataBroker { - async fn update_datapoints( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - // Collect errors encountered - let mut errors = HashMap::new(); - - let message = request.into_inner(); - let ids: Vec<(i32, broker::EntryUpdate)> = message - .datapoints - .iter() - .map(|(id, datapoint)| { - ( - *id, - broker::EntryUpdate { - path: None, - datapoint: Some(broker::Datapoint::from(datapoint)), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - ) - }) - .collect(); - - match broker.update_entries(ids).await { - Ok(()) => {} - Err(err) => { - debug!("Failed to set datapoint: {:?}", err); - errors = err - .iter() - .map(|(id, error)| (*id, proto::DatapointError::from(error) as i32)) - .collect(); - } - } - - Ok(Response::new(proto::UpdateDatapointsReply { errors })) - } - - type StreamDatapointsStream = ReceiverStream>; - - async fn stream_datapoints( - &self, - request: tonic::Request>, - ) -> Result, tonic::Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - - let mut stream = request.into_inner(); - - let mut shutdown_trigger = self.get_shutdown_trigger(); - - // Copy (to move into task below) - let broker = self.clone(); - - // Create error stream (to be returned) - let (error_sender, error_receiver) = mpsc::channel(10); - - // Listening on stream - tokio::spawn(async move { - let permissions = permissions; - let broker = broker.authorized_access(&permissions); - loop { - select! { - message = stream.message() => { - match message { - Ok(request) => { - match request { - Some(req) => { - let ids: Vec<(i32, broker::EntryUpdate)> = req.datapoints - .iter() - .map(|(id, datapoint)| - ( - *id, - broker::EntryUpdate { - path: None, - datapoint: Some(broker::Datapoint::from(datapoint)), - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - } - ) - ) - .collect(); - // TODO: Check if sender is allowed to provide datapoint with this id - match broker - .update_entries(ids) - .await - { - Ok(_) => {} - Err(err) => { - if let Err(err) = error_sender.send( - Ok(proto::StreamDatapointsReply { - errors: err.iter().map(|(id, error)| { - (*id, proto::DatapointError::from(error) as i32) - }).collect(), - }) - ).await { - debug!("Failed to send errors: {}", err); - } - } - } - }, - None => { - debug!("provider: no more messages"); - break; - } - } - }, - Err(err) => { - debug!("provider: connection broken: {:?}", err); - break; - }, - } - }, - _ = shutdown_trigger.recv() => { - debug!("provider: shutdown received"); - break; - } - } - } - }); - - // Return the error stream - Ok(Response::new(ReceiverStream::new(error_receiver))) - } - - async fn register_datapoints( - &self, - request: tonic::Request, - ) -> Result, Status> { - debug!(?request); - let permissions = match request.extensions().get::() { - Some(permissions) => { - debug!(?permissions); - permissions.clone() - } - None => return Err(tonic::Status::unauthenticated("Unauthenticated")), - }; - let broker = self.authorized_access(&permissions); - - let mut results = HashMap::new(); - let mut error = None; - - for metadata in request.into_inner().list { - match ( - proto::DataType::from_i32(metadata.data_type), - proto::ChangeType::from_i32(metadata.change_type), - ) { - (Some(value_type), Some(change_type)) => { - match broker - .add_entry( - metadata.name.clone(), - broker::DataType::from(&value_type), - broker::ChangeType::from(&change_type), - broker::types::EntryType::Sensor, - metadata.description, - None, - None, - ) - .await - { - Ok(id) => results.insert(metadata.name, id), - Err(RegistrationError::PermissionDenied) => { - // Registration error - error = Some(Status::new( - Code::PermissionDenied, - format!("Failed to register {}", metadata.name), - )); - break; - } - Err(RegistrationError::PermissionExpired) => { - // Registration error - error = Some(Status::new( - Code::Unauthenticated, - format!("Failed to register {}", metadata.name), - )); - break; - } - Err(RegistrationError::ValidationError) => { - // Registration error - error = Some(Status::new( - Code::InvalidArgument, - format!("Failed to register {}", metadata.name), - )); - break; - } - }; - } - (None, _) => { - // Invalid data type - error = Some(Status::new( - Code::InvalidArgument, - format!("Unsupported data type provided for {}", metadata.name), - )); - break; - } - (_, None) => { - // Invalid change type - error = Some(Status::new( - Code::InvalidArgument, - format!("Unsupported change type provided for {}", metadata.name), - )); - break; - } - } - } - - match error { - Some(error) => Err(error), - None => Ok(Response::new(proto::RegisterDatapointsReply { results })), - } - } -} diff --git a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/conversions.rs b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/conversions.rs deleted file mode 100644 index e028c3907..000000000 --- a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/conversions.rs +++ /dev/null @@ -1,330 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::sdv::databroker::v1 as proto; - -use prost_types::Timestamp; -use std::convert::TryInto; -use std::time::SystemTime; - -use crate::broker; - -impl From<&proto::Datapoint> for broker::Datapoint { - fn from(datapoint: &proto::Datapoint) -> Self { - let value = broker::DataValue::from(datapoint); - let ts = SystemTime::now(); - - match &datapoint.timestamp { - Some(source_timestamp) => { - let source: Option = match source_timestamp.clone().try_into() { - Ok(source) => Some(source), - Err(_) => None, - }; - broker::Datapoint { - ts, - source_ts: source, - value, - } - } - None => broker::Datapoint { - ts, - source_ts: None, - value, - }, - } - } -} - -impl From<&broker::Datapoint> for proto::Datapoint { - fn from(datapoint: &broker::Datapoint) -> Self { - let value = match &datapoint.value { - broker::DataValue::Bool(value) => proto::datapoint::Value::BoolValue(*value), - broker::DataValue::String(value) => { - proto::datapoint::Value::StringValue(value.to_owned()) - } - broker::DataValue::Int32(value) => proto::datapoint::Value::Int32Value(*value), - broker::DataValue::Int64(value) => proto::datapoint::Value::Int64Value(*value), - broker::DataValue::Uint32(value) => proto::datapoint::Value::Uint32Value(*value), - broker::DataValue::Uint64(value) => proto::datapoint::Value::Uint64Value(*value), - broker::DataValue::Float(value) => proto::datapoint::Value::FloatValue(*value), - broker::DataValue::Double(value) => proto::datapoint::Value::DoubleValue(*value), - broker::DataValue::BoolArray(array) => { - proto::datapoint::Value::BoolArray(proto::BoolArray { - values: array.clone(), - }) - } - broker::DataValue::StringArray(array) => { - proto::datapoint::Value::StringArray(proto::StringArray { - values: array.clone(), - }) - } - broker::DataValue::Int32Array(array) => { - proto::datapoint::Value::Int32Array(proto::Int32Array { - values: array.clone(), - }) - } - broker::DataValue::Int64Array(array) => { - proto::datapoint::Value::Int64Array(proto::Int64Array { - values: array.clone(), - }) - } - broker::DataValue::Uint32Array(array) => { - proto::datapoint::Value::Uint32Array(proto::Uint32Array { - values: array.clone(), - }) - } - broker::DataValue::Uint64Array(array) => { - proto::datapoint::Value::Uint64Array(proto::Uint64Array { - values: array.clone(), - }) - } - broker::DataValue::FloatArray(array) => { - proto::datapoint::Value::FloatArray(proto::FloatArray { - values: array.clone(), - }) - } - broker::DataValue::DoubleArray(array) => { - proto::datapoint::Value::DoubleArray(proto::DoubleArray { - values: array.clone(), - }) - } - broker::DataValue::NotAvailable => proto::datapoint::Value::FailureValue( - proto::datapoint::Failure::NotAvailable as i32, - ), - }; - - proto::Datapoint { - timestamp: Some(datapoint.ts.into()), - value: Some(value), - } - } -} - -impl From<&broker::QueryField> for proto::Datapoint { - fn from(query_field: &broker::QueryField) -> Self { - let value = match &query_field.value { - broker::DataValue::Bool(value) => proto::datapoint::Value::BoolValue(*value), - broker::DataValue::String(value) => { - proto::datapoint::Value::StringValue(value.to_owned()) - } - broker::DataValue::Int32(value) => proto::datapoint::Value::Int32Value(*value), - broker::DataValue::Int64(value) => proto::datapoint::Value::Int64Value(*value), - broker::DataValue::Uint32(value) => proto::datapoint::Value::Uint32Value(*value), - broker::DataValue::Uint64(value) => proto::datapoint::Value::Uint64Value(*value), - broker::DataValue::Float(value) => proto::datapoint::Value::FloatValue(*value), - broker::DataValue::Double(value) => proto::datapoint::Value::DoubleValue(*value), - broker::DataValue::BoolArray(array) => { - proto::datapoint::Value::BoolArray(proto::BoolArray { - values: array.clone(), - }) - } - broker::DataValue::StringArray(array) => { - proto::datapoint::Value::StringArray(proto::StringArray { - values: array.clone(), - }) - } - broker::DataValue::Int32Array(array) => { - proto::datapoint::Value::Int32Array(proto::Int32Array { - values: array.clone(), - }) - } - broker::DataValue::Int64Array(array) => { - proto::datapoint::Value::Int64Array(proto::Int64Array { - values: array.clone(), - }) - } - broker::DataValue::Uint32Array(array) => { - proto::datapoint::Value::Uint32Array(proto::Uint32Array { - values: array.clone(), - }) - } - broker::DataValue::Uint64Array(array) => { - proto::datapoint::Value::Uint64Array(proto::Uint64Array { - values: array.clone(), - }) - } - broker::DataValue::FloatArray(array) => { - proto::datapoint::Value::FloatArray(proto::FloatArray { - values: array.clone(), - }) - } - broker::DataValue::DoubleArray(array) => { - proto::datapoint::Value::DoubleArray(proto::DoubleArray { - values: array.clone(), - }) - } - broker::DataValue::NotAvailable => proto::datapoint::Value::FailureValue( - proto::datapoint::Failure::NotAvailable.into(), - ), - }; - - proto::Datapoint { - timestamp: Some(Timestamp::from(SystemTime::now())), - value: Some(value), - } - } -} - -impl From<&proto::DataType> for broker::DataType { - fn from(data_type: &proto::DataType) -> Self { - match data_type { - proto::DataType::Bool => broker::DataType::Bool, - proto::DataType::String => broker::DataType::String, - proto::DataType::Int8 => broker::DataType::Int8, - proto::DataType::Int16 => broker::DataType::Int16, - proto::DataType::Int32 => broker::DataType::Int32, - proto::DataType::Int64 => broker::DataType::Int64, - proto::DataType::Uint8 => broker::DataType::Uint8, - proto::DataType::Uint16 => broker::DataType::Uint16, - proto::DataType::Uint32 => broker::DataType::Uint32, - proto::DataType::Uint64 => broker::DataType::Uint64, - proto::DataType::Float => broker::DataType::Float, - proto::DataType::Double => broker::DataType::Double, - proto::DataType::StringArray => broker::DataType::StringArray, - proto::DataType::BoolArray => broker::DataType::BoolArray, - proto::DataType::Int8Array => broker::DataType::Int8Array, - proto::DataType::Int16Array => broker::DataType::Int16Array, - proto::DataType::Int32Array => broker::DataType::Int32Array, - proto::DataType::Int64Array => broker::DataType::Int64Array, - proto::DataType::Uint8Array => broker::DataType::Uint8Array, - proto::DataType::Uint16Array => broker::DataType::Uint16Array, - proto::DataType::Uint32Array => broker::DataType::Uint32Array, - proto::DataType::Uint64Array => broker::DataType::Uint64Array, - proto::DataType::FloatArray => broker::DataType::FloatArray, - proto::DataType::DoubleArray => broker::DataType::DoubleArray, - } - } -} - -impl From<&proto::Datapoint> for broker::DataValue { - fn from(datapoint: &proto::Datapoint) -> Self { - match &datapoint.value { - Some(value) => match value { - proto::datapoint::Value::StringValue(value) => { - broker::DataValue::String(value.to_owned()) - } - proto::datapoint::Value::BoolValue(value) => broker::DataValue::Bool(*value), - proto::datapoint::Value::Int32Value(value) => broker::DataValue::Int32(*value), - proto::datapoint::Value::Int64Value(value) => broker::DataValue::Int64(*value), - proto::datapoint::Value::Uint32Value(value) => broker::DataValue::Uint32(*value), - proto::datapoint::Value::Uint64Value(value) => broker::DataValue::Uint64(*value), - proto::datapoint::Value::FloatValue(value) => broker::DataValue::Float(*value), - proto::datapoint::Value::DoubleValue(value) => broker::DataValue::Double(*value), - proto::datapoint::Value::StringArray(array) => { - broker::DataValue::StringArray(array.values.clone()) - } - proto::datapoint::Value::BoolArray(array) => { - broker::DataValue::BoolArray(array.values.clone()) - } - proto::datapoint::Value::Int32Array(array) => { - broker::DataValue::Int32Array(array.values.clone()) - } - proto::datapoint::Value::Int64Array(array) => { - broker::DataValue::Int64Array(array.values.clone()) - } - proto::datapoint::Value::Uint32Array(array) => { - broker::DataValue::Uint32Array(array.values.clone()) - } - proto::datapoint::Value::Uint64Array(array) => { - broker::DataValue::Uint64Array(array.values.clone()) - } - proto::datapoint::Value::FloatArray(array) => { - broker::DataValue::FloatArray(array.values.clone()) - } - proto::datapoint::Value::DoubleArray(array) => { - broker::DataValue::DoubleArray(array.values.clone()) - } - proto::datapoint::Value::FailureValue(_) => broker::DataValue::NotAvailable, - }, - None => broker::DataValue::NotAvailable, - } - } -} - -impl From<&broker::DataType> for proto::DataType { - fn from(value_type: &broker::DataType) -> Self { - match value_type { - broker::DataType::Bool => proto::DataType::Bool, - broker::DataType::String => proto::DataType::String, - broker::DataType::Int8 => proto::DataType::Int8, - broker::DataType::Int16 => proto::DataType::Int16, - broker::DataType::Int32 => proto::DataType::Int32, - broker::DataType::Int64 => proto::DataType::Int64, - broker::DataType::Uint8 => proto::DataType::Uint8, - broker::DataType::Uint16 => proto::DataType::Uint16, - broker::DataType::Uint32 => proto::DataType::Uint32, - broker::DataType::Uint64 => proto::DataType::Uint64, - broker::DataType::Float => proto::DataType::Float, - broker::DataType::Double => proto::DataType::Double, - broker::DataType::StringArray => proto::DataType::StringArray, - broker::DataType::BoolArray => proto::DataType::BoolArray, - broker::DataType::Int8Array => proto::DataType::Int8Array, - broker::DataType::Int16Array => proto::DataType::Int16Array, - broker::DataType::Int32Array => proto::DataType::Int32Array, - broker::DataType::Int64Array => proto::DataType::Int64Array, - broker::DataType::Uint8Array => proto::DataType::Uint8Array, - broker::DataType::Uint16Array => proto::DataType::Uint16Array, - broker::DataType::Uint32Array => proto::DataType::Uint32Array, - broker::DataType::Uint64Array => proto::DataType::Uint64Array, - broker::DataType::FloatArray => proto::DataType::FloatArray, - broker::DataType::DoubleArray => proto::DataType::DoubleArray, - } - } -} - -impl From<&broker::EntryType> for proto::EntryType { - fn from(entry_type: &broker::EntryType) -> Self { - match entry_type { - broker::EntryType::Sensor => proto::EntryType::Sensor, - broker::EntryType::Attribute => proto::EntryType::Attribute, - broker::EntryType::Actuator => proto::EntryType::Actuator, - } - } -} - -impl From<&proto::ChangeType> for broker::ChangeType { - fn from(change_type: &proto::ChangeType) -> Self { - match change_type { - proto::ChangeType::OnChange => broker::ChangeType::OnChange, - proto::ChangeType::Continuous => broker::ChangeType::Continuous, - proto::ChangeType::Static => broker::ChangeType::Static, - } - } -} - -impl From<&broker::Metadata> for proto::Metadata { - fn from(metadata: &broker::Metadata) -> Self { - proto::Metadata { - id: metadata.id, - entry_type: proto::EntryType::from(&metadata.entry_type) as i32, - name: metadata.path.to_owned(), - data_type: proto::DataType::from(&metadata.data_type) as i32, - change_type: proto::ChangeType::Continuous as i32, // TODO: Add to metadata - description: metadata.description.to_owned(), - } - } -} - -impl From<&broker::UpdateError> for proto::DatapointError { - fn from(error: &broker::UpdateError) -> Self { - match error { - broker::UpdateError::NotFound => proto::DatapointError::UnknownDatapoint, - broker::UpdateError::WrongType | broker::UpdateError::UnsupportedType => { - proto::DatapointError::InvalidType - } - broker::UpdateError::OutOfBounds => proto::DatapointError::OutOfBounds, - broker::UpdateError::PermissionDenied => proto::DatapointError::AccessDenied, - broker::UpdateError::PermissionExpired => proto::DatapointError::AccessDenied, - } - } -} diff --git a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/mod.rs b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/mod.rs deleted file mode 100644 index 4888ffd5b..000000000 --- a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -mod broker; -mod collector; -mod conversions; diff --git a/kuksa_databroker/databroker/src/grpc/server.rs b/kuksa_databroker/databroker/src/grpc/server.rs deleted file mode 100644 index f3364a243..000000000 --- a/kuksa_databroker/databroker/src/grpc/server.rs +++ /dev/null @@ -1,189 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::{convert::TryFrom, future::Future, time::Duration}; - -use tokio::net::TcpListener; -use tokio_stream::wrappers::TcpListenerStream; -use tonic::transport::Server; -#[cfg(feature = "tls")] -use tonic::transport::ServerTlsConfig; -use tracing::{debug, info}; - -use databroker_proto::{kuksa, sdv}; - -use crate::{ - authorization::Authorization, - broker, - permissions::{self, Permissions}, -}; - -#[cfg(feature = "tls")] -pub enum ServerTLS { - Disabled, - Enabled { tls_config: ServerTlsConfig }, -} - -impl tonic::service::Interceptor for Authorization { - fn call( - &mut self, - mut request: tonic::Request<()>, - ) -> Result, tonic::Status> { - match self { - Authorization::Disabled => { - request - .extensions_mut() - .insert(permissions::ALLOW_ALL.clone()); - Ok(request) - } - Authorization::Enabled { token_decoder } => { - match request.metadata().get("authorization") { - Some(header) => match header.to_str() { - Ok(header) if header.starts_with("Bearer ") => { - let token: &str = header[7..].into(); - match token_decoder.decode(token) { - Ok(claims) => match Permissions::try_from(claims) { - Ok(permissions) => { - request.extensions_mut().insert(permissions); - Ok(request) - } - Err(err) => Err(tonic::Status::unauthenticated(format!( - "Invalid auth token: {err}" - ))), - }, - Err(err) => Err(tonic::Status::unauthenticated(format!( - "Invalid auth token: {err}" - ))), - } - } - Ok(_) | Err(_) => Err(tonic::Status::unauthenticated("Invalid auth token")), - }, - None => { - debug!("No auth token provided"); - Err(tonic::Status::unauthenticated("No auth token provided")) - } - } - } - } - } -} - -async fn shutdown(databroker: broker::DataBroker, signal: F) -where - F: Future, -{ - // Wait for signal - signal.await; - - info!("Shutting down"); - databroker.shutdown().await; -} - -pub async fn serve( - addr: impl Into, - broker: broker::DataBroker, - #[cfg(feature = "tls")] server_tls: ServerTLS, - authorization: Authorization, - signal: F, -) -> Result<(), Box> -where - F: Future, -{ - let socket_addr = addr.into(); - let listener = TcpListener::bind(socket_addr).await?; - - /* On Linux systems try to notify daemon readiness to systemd. - * This function determines whether the a system is using systemd - * or not, so it is safe to use on non-systemd systems as well. - */ - #[cfg(target_os = "linux")] - { - match sd_notify::booted() { - Ok(true) => { - info!("Notifying systemd that the service is ready"); - sd_notify::notify(false, &[sd_notify::NotifyState::Ready])?; - } - _ => { - debug!("System is not using systemd, will not try to notify"); - } - } - } - - serve_with_incoming_shutdown( - listener, - broker, - #[cfg(feature = "tls")] - server_tls, - authorization, - signal, - ) - .await -} - -pub async fn serve_with_incoming_shutdown( - listener: TcpListener, - broker: broker::DataBroker, - #[cfg(feature = "tls")] server_tls: ServerTLS, - authorization: Authorization, - signal: F, -) -> Result<(), Box> -where - F: Future, -{ - broker.start_housekeeping_task(); - if let Ok(addr) = listener.local_addr() { - info!("Listening on {}", addr); - } - - let incoming = TcpListenerStream::new(listener); - let mut builder = Server::builder() - .http2_keepalive_interval(Some(Duration::from_secs(10))) - .http2_keepalive_timeout(Some(Duration::from_secs(20))); - - #[cfg(feature = "tls")] - match server_tls { - ServerTLS::Enabled { tls_config } => { - info!("Using TLS"); - builder = builder.tls_config(tls_config)?; - } - ServerTLS::Disabled => { - info!("TLS is not enabled") - } - } - - if let Authorization::Disabled = &authorization { - info!("Authorization is not enabled."); - } - - builder - .add_service( - sdv::databroker::v1::broker_server::BrokerServer::with_interceptor( - broker.clone(), - authorization.clone(), - ), - ) - .add_service( - sdv::databroker::v1::collector_server::CollectorServer::with_interceptor( - broker.clone(), - authorization.clone(), - ), - ) - .add_service(kuksa::val::v1::val_server::ValServer::with_interceptor( - broker.clone(), - authorization, - )) - .serve_with_incoming_shutdown(incoming, shutdown(broker, signal)) - .await?; - - Ok(()) -} diff --git a/kuksa_databroker/databroker/src/lib.rs b/kuksa_databroker/databroker/src/lib.rs deleted file mode 100644 index 49672dba5..000000000 --- a/kuksa_databroker/databroker/src/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -pub mod authorization; -pub mod broker; -pub mod glob; -pub mod grpc; -pub mod permissions; -pub mod query; -pub mod types; -pub mod vss; - -#[cfg(feature = "viss")] -pub mod viss; - -use std::fmt::Write; - -use tracing::info; -use tracing_subscriber::filter::EnvFilter; - -pub fn init_logging() { - let mut output = String::from("Init logging from RUST_LOG"); - let filter = EnvFilter::try_from_default_env().unwrap_or_else(|err| { - output.write_fmt(format_args!(" ({err})")).unwrap(); - // If no environment variable set, this is the default - EnvFilter::new("info") - }); - tracing_subscriber::fmt::Subscriber::builder() - .with_env_filter(filter) - .try_init() - .expect("Unable to install global logging subscriber"); - - info!("{}", output); -} diff --git a/kuksa_databroker/databroker/src/main.rs b/kuksa_databroker/databroker/src/main.rs deleted file mode 100644 index f0abcf0a4..000000000 --- a/kuksa_databroker/databroker/src/main.rs +++ /dev/null @@ -1,455 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022-2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -#[cfg(feature = "jemalloc")] -#[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; - -use databroker::authorization::Authorization; -use databroker::broker::RegistrationError; - -#[cfg(feature = "tls")] -use databroker::grpc::server::ServerTLS; - -use tokio::select; -use tokio::signal::unix::{signal, SignalKind}; -#[cfg(feature = "tls")] -use tracing::warn; -use tracing::{debug, error, info}; - -use clap::{Arg, ArgAction, Command}; - -#[cfg(feature = "viss")] -use databroker::viss; -use databroker::{broker, grpc, permissions, vss}; - -async fn shutdown_handler() { - let mut sigint = - signal(SignalKind::interrupt()).expect("failed to setup SIGINT signal handler"); - let mut sighup = signal(SignalKind::hangup()).expect("failed to setup SIGHUP signal handler"); - let mut sigterm = - signal(SignalKind::terminate()).expect("failed to setup SIGTERM signal handler"); - - select! { - _ = sigint.recv() => info!("received SIGINT"), - _ = sighup.recv() => info!("received SIGHUP"), - _ = sigterm.recv() => info!("received SIGTERM"), - }; -} - -async fn add_kuksa_attribute( - database: &broker::AuthorizedAccess<'_, '_>, - attribute: String, - value: String, - description: String, -) { - debug!("Adding attribute {}", attribute); - - match database - .add_entry( - attribute.clone(), - databroker::broker::DataType::String, - databroker::broker::ChangeType::OnChange, - databroker::broker::EntryType::Attribute, - description, - None, - None, - ) - .await - { - Ok(id) => { - let ids = [( - id, - broker::EntryUpdate { - datapoint: Some(broker::Datapoint { - ts: std::time::SystemTime::now(), - source_ts: None, - value: broker::types::DataValue::String(value), - }), - path: None, - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]; - if let Err(errors) = database.update_entries(ids).await { - // There's only one error (since we're only trying to set one) - if let Some(error) = errors.first() { - info!("Failed to set value for {}: {:?}", attribute, error.1); - } - } - } - Err(RegistrationError::PermissionDenied) => { - error!("Failed to add entry {attribute}: Permission denied") - } - Err(RegistrationError::PermissionExpired) => { - error!("Failed to add entry {attribute}: Permission expired") - } - Err(RegistrationError::ValidationError) => { - error!("Failed to add entry {attribute}: Validation failed") - } - } -} - -async fn read_metadata_file<'a, 'b>( - database: &broker::AuthorizedAccess<'_, '_>, - filename: &str, -) -> Result<(), Box> { - let path = filename.trim(); - info!("Populating metadata from file '{}'", path); - let metadata_file = std::fs::OpenOptions::new().read(true).open(filename)?; - let entries = vss::parse_vss_from_reader(&metadata_file)?; - - for (path, entry) in entries { - debug!("Adding VSS datapoint type {}", path); - - match database - .add_entry( - path.clone(), - entry.data_type, - entry.change_type, - entry.entry_type, - entry.description, - entry.allowed, - entry.unit, - ) - .await - { - Ok(id) => { - if let Some(default) = entry.default { - let ids = [( - id, - broker::EntryUpdate { - datapoint: Some(broker::Datapoint { - ts: std::time::SystemTime::now(), - source_ts: None, - value: default, - }), - path: None, - actuator_target: None, - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }, - )]; - if let Err(errors) = database.update_entries(ids).await { - // There's only one error (since we're only trying to set one) - if let Some(error) = errors.first() { - info!("Failed to set default value for {}: {:?}", path, error.1); - } - } - } - } - Err(RegistrationError::PermissionDenied) => { - error!("Failed to add entry {path}: Permission denied") - } - Err(RegistrationError::PermissionExpired) => { - error!("Failed to add entry {path}: Permission expired") - } - Err(RegistrationError::ValidationError) => { - error!("Failed to add entry {path}: Validation failed") - } - } - } - Ok(()) -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let version = option_env!("VERGEN_GIT_SEMVER_LIGHTWEIGHT") - .unwrap_or(option_env!("VERGEN_GIT_SHA").unwrap_or("unknown")); - - let about = format!( - concat!( - "\n Commit Date: {}", - "\n Commit SHA: {}", - "\n Commit Branch: {}", - "\n", - "\n Package version: {}", - "\n Debug build: {}" - ), - option_env!("VERGEN_GIT_COMMIT_TIMESTAMP").unwrap_or(""), - option_env!("VERGEN_GIT_SHA").unwrap_or(""), - option_env!("VERGEN_GIT_BRANCH").unwrap_or(""), - option_env!("CARGO_PKG_VERSION").unwrap_or(""), - option_env!("VERGEN_CARGO_DEBUG").unwrap_or(""), - ); - - let mut parser = Command::new("Kuksa Data Broker"); - parser = parser - .version(version) - .about(about) - .arg( - Arg::new("address") - .display_order(1) - .long("address") - .alias("addr") - .help("Bind address") - .action(ArgAction::Set) - .value_name("IP") - .required(false) - .env("KUKSA_DATA_BROKER_ADDR") - .default_value("127.0.0.1"), - ) - .arg( - Arg::new("port") - .display_order(2) - .long("port") - .help("Bind port") - .action(ArgAction::Set) - .value_name("PORT") - .required(false) - .env("KUKSA_DATA_BROKER_PORT") - .value_parser(clap::value_parser!(u16)) - .default_value("55555"), - ) - .arg( - Arg::new("vss-file") - .display_order(4) - .alias("metadata") - .long("vss") - .help("Populate data broker with VSS metadata from (comma-separated) list of files") - .action(ArgAction::Set) - .value_delimiter(',') - .value_name("FILE") - .env("KUKSA_DATA_BROKER_METADATA_FILE") - .value_parser(clap::builder::NonEmptyStringValueParser::new()) - .required(false), - ) - .arg( - Arg::new("jwt-public-key") - .display_order(5) - .long("jwt-public-key") - .help("Public key used to verify JWT access tokens") - .action(ArgAction::Set) - .value_name("FILE") - .required(false), - ) - .arg( - Arg::new("disable-authorization") - .display_order(6) - .long("disable-authorization") - .help("Disable authorization") - .action(ArgAction::SetTrue), - ); - - #[cfg(feature = "tls")] - { - parser = parser - .arg( - Arg::new("insecure") - .display_order(20) - .long("insecure") - .help("Allow insecure connections") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("tls-cert") - .display_order(21) - .long("tls-cert") - .help("TLS certificate file (.pem)") - .action(ArgAction::Set) - .value_name("FILE") - .conflicts_with("insecure"), - ) - .arg( - Arg::new("tls-private-key") - .display_order(22) - .long("tls-private-key") - .help("TLS private key file (.key)") - .action(ArgAction::Set) - .value_name("FILE") - .conflicts_with("insecure"), - ); - } - - #[cfg(feature = "viss")] - { - parser = parser - .arg( - Arg::new("enable-viss") - .display_order(30) - .long("enable-viss") - .help("Enable VISSv2 (websocket) service") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("viss-address") - .display_order(31) - .long("viss-address") - .help("VISS address") - .action(ArgAction::Set) - .value_name("IP") - .required(false) - .env("KUKSA_DATABROKER_VISS_ADDR") - .default_value("127.0.0.1"), - ) - .arg( - Arg::new("viss-port") - .display_order(32) - .long("viss-port") - .help("VISS port") - .action(ArgAction::Set) - .value_name("PORT") - .required(false) - .env("KUKSA_DATABROKER_VISS_PORT") - .value_parser(clap::value_parser!(u16)) - .default_value("8090"), - ); - } - - let args = parser.get_matches(); - - // install global collector configured based on RUST_LOG env var. - databroker::init_logging(); - - info!("Starting Kuksa Databroker {}", version); - warn!("Databroker has been migrated to https://github.com/eclipse-kuksa/kuksa-databroker"); - warn!("Consider migrating to the new repository!"); - - let ip_addr = args.get_one::("address").unwrap().parse()?; - let port = args - .get_one::("port") - .expect("port should be a number"); - let addr = std::net::SocketAddr::new(ip_addr, *port); - - let broker = broker::DataBroker::new(version); - let database = broker.authorized_access(&permissions::ALLOW_ALL); - - add_kuksa_attribute( - &database, - "Kuksa.Databroker.GitVersion".to_owned(), - option_env!("VERGEN_GIT_SEMVER_LIGHTWEIGHT") - .unwrap_or("N/A") - .to_owned(), - "Databroker version as reported by GIT".to_owned(), - ) - .await; - - add_kuksa_attribute( - &database, - "Kuksa.Databroker.CargoVersion".to_owned(), - option_env!("CARGO_PKG_VERSION").unwrap_or("N/A").to_owned(), - "Databroker version as reported by GIT".to_owned(), - ) - .await; - - add_kuksa_attribute( - &database, - "Kuksa.Databroker.CommitSha".to_owned(), - option_env!("VERGEN_GIT_SHA").unwrap_or("N/A").to_owned(), - "Commit SHA of current version".to_owned(), - ) - .await; - - if let Some(metadata_filenames) = args.get_many::("vss-file") { - for filename in metadata_filenames { - read_metadata_file(&database, filename).await?; - } - } - - #[cfg(feature = "tls")] - let tls_config = if args.get_flag("insecure") { - ServerTLS::Disabled - } else { - let cert_file = args.get_one::("tls-cert"); - let key_file = args.get_one::("tls-private-key"); - match (cert_file, key_file) { - (Some(cert_file), Some(key_file)) => { - let cert = std::fs::read(cert_file)?; - let key = std::fs::read(key_file)?; - let identity = tonic::transport::Identity::from_pem(cert, key); - ServerTLS::Enabled { - tls_config: tonic::transport::ServerTlsConfig::new().identity(identity), - } - } - (Some(_), None) => { - return Err( - "TLS private key (--tls-private-key) must be set if --tls-cert is.".into(), - ); - } - (None, Some(_)) => { - return Err( - "TLS certificate (--tls-cert) must be set if --tls-private-key is.".into(), - ); - } - (None, None) => { - warn!( - "TLS is not enabled. Default behavior of accepting insecure connections \ - when TLS is not configured may change in the future! \ - Please use --insecure to explicitly enable this behavior." - ); - ServerTLS::Disabled - } - } - }; - - let enable_authorization = !args.get_flag("disable-authorization"); - let jwt_public_key = match args.get_one::("jwt-public-key") { - Some(pub_key_filename) => match std::fs::read_to_string(pub_key_filename) { - Ok(pub_key) => { - info!("Using '{pub_key_filename}' to authenticate access tokens"); - Ok(Some(pub_key)) - } - Err(err) => { - error!("Failed to open file {:?}: {}", pub_key_filename, err); - Err(err) - } - }, - None => Ok(None), - }?; - - let authorization = match (enable_authorization, jwt_public_key) { - (true, Some(pub_key)) => Authorization::new(pub_key)?, - (true, None) => { - warn!("Authorization is not enabled."); - Authorization::Disabled - } - (false, _) => Authorization::Disabled, - }; - - #[cfg(feature = "viss")] - { - let viss_port = args - .get_one::("viss-port") - .expect("port should be a number"); - let viss_addr = std::net::SocketAddr::new(ip_addr, *viss_port); - - if args.get_flag("enable-viss") { - let broker = broker.clone(); - let authorization = authorization.clone(); - tokio::spawn(async move { - if let Err(err) = viss::server::serve(viss_addr, broker, authorization).await { - error!("{err}"); - } - }); - } - } - - grpc::server::serve( - addr, - broker, - #[cfg(feature = "tls")] - tls_config, - authorization, - shutdown_handler(), - ) - .await?; - - Ok(()) -} diff --git a/kuksa_databroker/databroker/src/permissions.rs b/kuksa_databroker/databroker/src/permissions.rs deleted file mode 100644 index 7da1eae1f..000000000 --- a/kuksa_databroker/databroker/src/permissions.rs +++ /dev/null @@ -1,295 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::time::SystemTime; - -use lazy_static::lazy_static; -use regex::RegexSet; - -use crate::glob; - -lazy_static! { - pub static ref ALLOW_ALL: Permissions = Permissions { - expires_at: None, - read: PathMatcher::Everything, - actuate: PathMatcher::Everything, - provide: PathMatcher::Everything, - create: PathMatcher::Everything, - }; - pub static ref ALLOW_NONE: Permissions = Permissions { - expires_at: None, - read: PathMatcher::Nothing, - actuate: PathMatcher::Nothing, - provide: PathMatcher::Nothing, - create: PathMatcher::Nothing, - }; -} - -#[derive(Debug, Clone)] -pub struct Permissions { - expires_at: Option, - read: PathMatcher, - actuate: PathMatcher, - provide: PathMatcher, - create: PathMatcher, -} - -pub struct PermissionBuilder { - expiration: Option, - read: PathMatchBuilder, - actuate: PathMatchBuilder, - provide: PathMatchBuilder, - create: PathMatchBuilder, -} - -pub enum Permission { - Nothing, - All, - Glob(String), -} - -pub enum PathMatchBuilder { - Nothing, - Everything, - Globs(Vec), -} - -#[derive(Debug, Clone)] -pub enum PathMatcher { - Nothing, - Everything, - Regexps(regex::RegexSet), -} - -#[derive(Debug)] -pub enum PermissionError { - Denied, - Expired, -} - -#[derive(Debug)] -pub enum PermissionsBuildError { - BuildError, -} - -impl Default for PermissionBuilder { - fn default() -> Self { - Self::new() - } -} - -impl PermissionBuilder { - pub fn new() -> Self { - Self { - expiration: None, - read: PathMatchBuilder::Nothing, - actuate: PathMatchBuilder::Nothing, - provide: PathMatchBuilder::Nothing, - create: PathMatchBuilder::Nothing, - } - } - - pub fn expires_at(mut self, expiration: SystemTime) -> Self { - self.expiration = Some(expiration); - self - } - - pub fn add_read_permission(mut self, permission: Permission) -> Self { - match permission { - Permission::Nothing => { - // Adding nothing - } - Permission::All => self.read.extend_with(PathMatchBuilder::Everything), - Permission::Glob(path) => self.read.extend_with_glob(path), - }; - self - } - - pub fn add_actuate_permission(mut self, permission: Permission) -> Self { - match permission { - Permission::Nothing => { - // Adding nothing - } - Permission::All => self.actuate.extend_with(PathMatchBuilder::Everything), - Permission::Glob(path) => self.actuate.extend_with_glob(path), - }; - self - } - - pub fn add_provide_permission(mut self, permission: Permission) -> Self { - match permission { - Permission::Nothing => { - // Adding nothing - } - Permission::All => self.provide.extend_with(PathMatchBuilder::Everything), - Permission::Glob(path) => self.provide.extend_with_glob(path), - }; - self - } - - pub fn add_create_permission(mut self, permission: Permission) -> Self { - match permission { - Permission::Nothing => { - // Adding nothing - } - Permission::All => self.create.extend_with(PathMatchBuilder::Everything), - Permission::Glob(path) => self.create.extend_with_glob(path), - }; - self - } - - pub fn build(self) -> Result { - Ok(Permissions { - expires_at: self.expiration, - read: self.read.build()?, - actuate: self.actuate.build()?, - provide: self.provide.build()?, - create: self.create.build()?, - }) - } -} - -impl Permissions { - pub fn builder() -> PermissionBuilder { - PermissionBuilder::new() - } - - pub fn can_read(&self, path: &str) -> Result<(), PermissionError> { - self.expired()?; - - if self.read.is_match(path) { - return Ok(()); - } - - // Read permissions are included (by convention) in the - // other permissions as well. - if self.actuate.is_match(path) { - return Ok(()); - } - if self.provide.is_match(path) { - return Ok(()); - } - if self.create.is_match(path) { - return Ok(()); - } - - Err(PermissionError::Denied) - } - - pub fn can_write_actuator_target(&self, path: &str) -> Result<(), PermissionError> { - self.expired()?; - - if self.actuate.is_match(path) { - return Ok(()); - } - Err(PermissionError::Denied) - } - - pub fn can_write_datapoint(&self, path: &str) -> Result<(), PermissionError> { - self.expired()?; - - if self.provide.is_match(path) { - return Ok(()); - } - Err(PermissionError::Denied) - } - - pub fn can_create(&self, path: &str) -> Result<(), PermissionError> { - self.expired()?; - - if self.create.is_match(path) { - return Ok(()); - } - Err(PermissionError::Denied) - } - - #[inline] - pub fn expired(&self) -> Result<(), PermissionError> { - if let Some(expires_at) = self.expires_at { - if expires_at < SystemTime::now() { - return Err(PermissionError::Expired); - } - } - Ok(()) - } -} - -impl PathMatcher { - pub fn is_match(&self, path: &str) -> bool { - match self { - PathMatcher::Nothing => false, - PathMatcher::Everything => true, - PathMatcher::Regexps(regexps) => regexps.is_match(path), - } - } -} - -impl PathMatchBuilder { - pub fn extend_with(&mut self, other: PathMatchBuilder) { - if let PathMatchBuilder::Everything = self { - // We already allow everything - return; - } - - match other { - PathMatchBuilder::Nothing => { - // No change - } - PathMatchBuilder::Everything => { - // We now allow everything - *self = PathMatchBuilder::Everything - } - PathMatchBuilder::Globs(mut other_regexps) => match self { - PathMatchBuilder::Nothing => *self = PathMatchBuilder::Globs(other_regexps), - PathMatchBuilder::Everything => { - // We already allow everything - } - PathMatchBuilder::Globs(regexps) => { - // Combine regexps - regexps.append(&mut other_regexps) - } - }, - } - } - - pub fn extend_with_glob(&mut self, glob: String) { - match self { - PathMatchBuilder::Nothing => *self = PathMatchBuilder::Globs(vec![glob]), - PathMatchBuilder::Everything => { - // We already allow everything - } - PathMatchBuilder::Globs(globs) => { - // Combine regexps - globs.push(glob) - } - } - } - - pub fn build(self) -> Result { - match self { - PathMatchBuilder::Nothing => Ok(PathMatcher::Nothing), - PathMatchBuilder::Everything => Ok(PathMatcher::Everything), - PathMatchBuilder::Globs(globs) => { - let regexps = globs.iter().map(|glob| glob::to_regex_string(glob)); - - Ok(PathMatcher::Regexps(RegexSet::new(regexps).map_err( - |err| match err { - regex::Error::Syntax(_) => PermissionsBuildError::BuildError, - regex::Error::CompiledTooBig(_) => PermissionsBuildError::BuildError, - _ => PermissionsBuildError::BuildError, - }, - )?)) - } - } - } -} diff --git a/kuksa_databroker/databroker/src/query/compiler.rs b/kuksa_databroker/databroker/src/query/compiler.rs deleted file mode 100644 index e7c4f33a9..000000000 --- a/kuksa_databroker/databroker/src/query/compiler.rs +++ /dev/null @@ -1,548 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use super::expr::*; - -use sqlparser::ast; - -use crate::types::{DataType, DataValue}; - -use std::collections::{HashMap, HashSet}; - -#[derive(Debug)] -pub enum CompilationError { - UnknownField(String), - MalformedNumber(String), - UnsupportedOperator(String), - UnsupportedOperation(String), - TypeError(String), - InvalidLogic(String), - InvalidComparison(String), - ParseError(String), -} - -pub trait CompilationInput { - fn get_datapoint_type(&self, field: &str) -> Result; -} - -pub struct CompilationInputImpl { - pub schema: HashMap, // Needed datapoints (types) for compilation -} - -impl CompilationInputImpl { - pub fn new() -> Self { - Self { - schema: Default::default(), - } - } - - pub fn add_entry(&mut self, name: &str, data_type: &DataType) { - self.schema.insert(name.to_owned(), data_type.to_owned()); - } -} - -impl Default for CompilationInputImpl { - fn default() -> Self { - Self::new() - } -} -impl CompilationInput for CompilationInputImpl { - fn get_datapoint_type(&self, field: &str) -> Result { - match self.schema.get(field) { - Some(v) => Ok(v.clone()), - None => Err(CompilationError::UnknownField(field.to_owned())), - } - } -} - -#[derive(Debug)] -pub struct CompiledQuery { - /// A single expression (tree) evaluating to either - /// true or false. - pub selection: Option, // WHERE {selection} - - /// Each `Expr` in this vector produces a value upon - /// execution. - pub projection: Vec, // SELECT {projection} - - /// Full list of datapoint id:s of interest, - /// either specified in the SELECT statement, - /// or as part of a condition. - /// - /// These needs to be provided in the `input` when - /// executing the query. - pub input_spec: HashSet, // Needed datapoints (values) for execution - - /// Vector of subquery in SELECT query - pub subquery: Vec, -} - -impl CompiledQuery { - pub fn new() -> Self { - CompiledQuery { - selection: None, - projection: Vec::new(), - input_spec: HashSet::new(), - subquery: Vec::new(), - } - } -} - -impl Default for CompiledQuery { - fn default() -> Self { - Self::new() - } -} - -pub fn compile_expr( - expr: &ast::Expr, - input: &impl CompilationInput, - output: &mut CompiledQuery, -) -> Result { - match expr { - ast::Expr::Value(ast::Value::Number(n, _)) => { - Ok(Expr::UnresolvedLiteral { raw: n.to_owned() }) - } - ast::Expr::Value(ast::Value::SingleQuotedString(ref s)) => Ok(Expr::ResolvedLiteral { - value: DataValue::String(s.clone()), - data_type: DataType::String, - }), - - ast::Expr::Value(ast::Value::Boolean(n)) => Ok(Expr::ResolvedLiteral { - value: DataValue::Bool(*n), - data_type: DataType::Bool, - }), - - ast::Expr::Value(ast::Value::DoubleQuotedString(s)) => Ok(Expr::ResolvedLiteral { - value: DataValue::String(s.clone()), - data_type: DataType::String, - }), - - ast::Expr::Identifier(ref id) => { - let name = &id.value; - - // Does the datapoint exist? - let data_type = input.get_datapoint_type(name)?; - output.input_spec.insert(name.clone()); - Ok(Expr::Datapoint { - name: name.clone(), - data_type, - lag: false, - }) - } - - ast::Expr::CompoundIdentifier(ids) => { - let string_ids: Vec<&str> = ids.iter().map(|id| id.value.as_ref()).collect(); - let field = string_ids.join("."); - - // Does the datapoint exist? - let data_type = input.get_datapoint_type(&field)?; - output.input_spec.insert(field.clone()); - Ok(Expr::Datapoint { - name: field, - data_type, - lag: false, - }) - } - ast::Expr::Function(f) => { - let name = &f.name.to_string(); - if name == "LAG" { - let args = &f.args[0]; - match args { - ast::FunctionArg::Unnamed(e) => match e { - ast::FunctionArgExpr::Expr(e) => { - let function_expr = compile_expr(e, input, output)?; - match function_expr { - Expr::Datapoint { - name, data_type, .. - } => Ok(Expr::Datapoint { - name, - data_type, - lag: true, - }), - _ => Err(CompilationError::ParseError( - "Unable to create lag datapoint".to_string(), - )), - } - } - _ => Err(CompilationError::UnsupportedOperator( - "Unsupported function argument expression".to_string(), - )), - }, - _ => Err(CompilationError::UnsupportedOperator( - "Unsupported function argument".to_string(), - )), - } - } else { - Err(CompilationError::UnsupportedOperator(format!( - "Unsupported operator \"{name}\"" - ))) - } - } - - ast::Expr::BinaryOp { - ref left, - ref op, - ref right, - } => { - // Resolve unresolved literals if any - let (left_expr, right_expr) = { - let left_expr = compile_expr(left, input, output)?; - let right_expr = compile_expr(right, input, output)?; - - match (left_expr.get_type(), right_expr.get_type()) { - (Err(literal), Ok(right_type)) => match resolve_literal(literal, right_type) { - Ok(left_expr) => (Box::new(left_expr), Box::new(right_expr)), - Err(_) => { - return Err(CompilationError::TypeError(format!( - "left side is incompatible with right side in expression \"{expr}\"" - ))) - } - }, - (Ok(left_type), Err(literal)) => match resolve_literal(literal, left_type) { - Ok(right_expr) => (Box::new(left_expr), Box::new(right_expr)), - Err(_) => { - return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{expr}\"" - ))) - } - }, - (Err(left_literal), Err(right_literal)) => { - match (left_literal, right_literal) { - ( - UnresolvedLiteral::Number(raw_left), - UnresolvedLiteral::Number(raw_right), - ) => { - // Try to resolve to unresolved literals by parsing them together - match (raw_left.parse::(), raw_right.parse::()) { - (Ok(left_value), Ok(right_value)) => ( - Box::new(Expr::ResolvedLiteral { - value: DataValue::Int64(left_value), - data_type: DataType::Int64, - }), - Box::new(Expr::ResolvedLiteral { - value: DataValue::Int64(right_value), - data_type: DataType::Int64, - }), - ), - _ => { - match (raw_left.parse::(), raw_right.parse::()) { - (Ok(left_value), Ok(right_value)) => ( - Box::new(Expr::ResolvedLiteral { - value: DataValue::Uint64(left_value), - data_type: DataType::Uint64, - }), - Box::new(Expr::ResolvedLiteral { - value: DataValue::Uint64(right_value), - data_type: DataType::Uint64, - }), - ), - _ => match ( - raw_left.parse::(), - raw_right.parse::(), - ) { - (Ok(left_value), Ok(right_value)) => ( - Box::new(Expr::ResolvedLiteral { - value: DataValue::Double(left_value), - data_type: DataType::Double, - }), - Box::new(Expr::ResolvedLiteral { - value: DataValue::Double(right_value), - data_type: DataType::Double, - }), - ), - _ => return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{expr}\"" - ))) - }, - } - } - } - } - _ => { - return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{expr}\"" - ))) - } - } - } - (Ok(_), Ok(_)) => (Box::new(left_expr), Box::new(right_expr)), - } - }; - match op { - ast::BinaryOperator::Gt => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Gt, - right: right_expr, - }), - ast::BinaryOperator::GtEq => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Ge, - right: right_expr, - }), - ast::BinaryOperator::Lt => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Lt, - right: right_expr, - }), - ast::BinaryOperator::LtEq => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Le, - right: right_expr, - }), - ast::BinaryOperator::Eq => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Eq, - right: right_expr, - }), - ast::BinaryOperator::NotEq => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::NotEq, - right: right_expr, - }), - ast::BinaryOperator::And => match (left_expr.get_type(), right_expr.get_type()) { - (Ok(DataType::Bool), Ok(DataType::Bool)) => Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::And, - right: right_expr, - }), - _ => Err(CompilationError::TypeError( - "AND requires boolean expressions on both sides".to_string(), - )), - }, - ast::BinaryOperator::Or => match (left_expr.get_type(), right_expr.get_type()) { - (Ok(DataType::Bool), Ok(DataType::Bool)) => { - // It's all good man - Ok(Expr::BinaryOperation { - left: left_expr, - operator: Operator::Or, - right: right_expr, - }) - } - _ => Err(CompilationError::TypeError( - "OR requires boolean expressions on both sides".to_string(), - )), - }, - operator => Err(CompilationError::UnsupportedOperator( - format!("{operator}",), - )), - } - } - ast::Expr::Nested(e) => compile_expr(e, input, output), - - ast::Expr::Subquery(q) => { - let select_statement = match &q.body { - sqlparser::ast::SetExpr::Select(query) => Some(query.clone()), - _ => None, - }; - if let Some(select) = select_statement { - let compiled_query = compile_select_statement(&select, input); - match compiled_query { - Ok(compiled_query) => { - output.subquery.push(compiled_query); - Ok(Expr::Subquery { - index: (output.subquery.len() - 1) as u32, - }) - } - - _ => Err(CompilationError::UnsupportedOperator( - "Subquery failed to compile query".to_string(), - )), - } - } else { - Err(CompilationError::UnsupportedOperation( - "Subquery to parse".to_string(), - )) - } - } - - ast::Expr::UnaryOp { ref op, ref expr } => match op { - ast::UnaryOperator::Not => Ok(Expr::UnaryOperation { - expr: Box::new(compile_expr(expr, input, output)?), - operator: UnaryOperator::Not, - }), - operator => Err(CompilationError::UnsupportedOperator(format!( - "Unsupported unary operator \"{operator}\"" - ))), - }, - - ast::Expr::Between { - ref expr, - ref negated, - ref low, - ref high, - } => Ok(Expr::Between { - expr: Box::new(compile_expr(expr, input, output)?), - negated: *negated, - low: Box::new(compile_expr(low, input, output)?), - high: Box::new(compile_expr(high, input, output)?), - }), - operator => Err(CompilationError::UnsupportedOperator(format!( - "Unsupported operator \"{operator}\"" - ))), - } -} - -fn resolve_literal( - unresolved_literal: UnresolvedLiteral, - wanted_type: DataType, -) -> Result { - match (wanted_type, unresolved_literal) { - (DataType::Int8, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Int32(value as i32), - data_type: DataType::Int8, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Int16, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Int32(value as i32), - data_type: DataType::Int16, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Int32, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Int32(value), - data_type: DataType::Int32, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Int64, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Int64(value), - data_type: DataType::Int64, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Uint8, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Uint32(value as u32), - data_type: DataType::Uint8, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Uint16, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Uint32(value as u32), - data_type: DataType::Uint16, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Uint32, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Uint32(value), - data_type: DataType::Uint32, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Uint64, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Uint64(value), - data_type: DataType::Uint64, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Float, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Float(value), - data_type: DataType::Float, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - (DataType::Double, UnresolvedLiteral::Number(raw)) => match raw.parse::() { - Ok(value) => Ok(Expr::ResolvedLiteral { - value: DataValue::Double(value), - data_type: DataType::Double, - }), - Err(_) => Err(UnresolvedLiteral::Error), - }, - _ => Err(UnresolvedLiteral::Error), - } -} - -fn compile_select_statement( - select: &ast::Select, - input: &impl CompilationInput, -) -> Result { - let mut query = CompiledQuery::new(); - - match &select.selection { - None => {} - Some(expr) => { - let condition = compile_expr(expr, input, &mut query)?; - if let Ok(data_type) = condition.get_type() { - if data_type != DataType::Bool { - return Err(CompilationError::TypeError( - "WHERE statement doesn't evaluate to a boolean expression".to_string(), - )); - } - } - - query.selection = Some(condition); - } - }; - - for c in &select.projection { - match c { - ast::SelectItem::UnnamedExpr(expr) => { - let expr = compile_expr(expr, input, &mut query)?; - query.projection.push(expr); - } - ast::SelectItem::ExprWithAlias { expr, alias } => { - let expr = compile_expr(expr, input, &mut query)?; - - let name = alias.value.clone(); - query.projection.push(Expr::Alias { - expr: Box::new(expr), - alias: name, - }); - } - _ => { - return Err(CompilationError::UnsupportedOperation( - "unrecognized entry in SELECT statement".to_string(), - )) - } - } - } - - Ok(query) -} - -pub fn compile( - sql: &str, - input: &impl CompilationInput, -) -> Result { - let dialect = sqlparser::dialect::GenericDialect {}; - - match sqlparser::parser::Parser::parse_sql(&dialect, sql) { - Ok(ast) => { - let select_statement = match &ast.first() { - Some(sqlparser::ast::Statement::Query(q)) => match &q.body { - sqlparser::ast::SetExpr::Select(query) => Some(query.clone()), - _ => None, - }, - _ => None, - }; - if let Some(select) = select_statement { - compile_select_statement(&select, input) - } else { - Err(CompilationError::UnsupportedOperation( - "unrecognized SELECT statement".to_string(), - )) - } - } - Err(e) => Err(CompilationError::ParseError(format!("{e}"))), - } -} diff --git a/kuksa_databroker/databroker/src/query/executor.rs b/kuksa_databroker/databroker/src/query/executor.rs deleted file mode 100644 index afbd99324..000000000 --- a/kuksa_databroker/databroker/src/query/executor.rs +++ /dev/null @@ -1,647 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::collections::HashMap; - -use super::compiler::CompiledQuery; -use super::expr::*; - -use crate::types::{DataValue, ExecutionInputImplData}; - -#[derive(Debug)] -pub enum ExecutionError { - GeneralError(String), - TypeError(String), - CastError(String), -} - -#[derive(Debug)] -pub struct ExecutionInputImpl { - fields: HashMap, -} - -pub trait ExecutionInput { - fn lookup(&self, field: &str) -> &ExecutionInputImplData; - - fn get_fields(&self) -> &HashMap; -} - -impl CompiledQuery { - fn execute_internal( - query: &CompiledQuery, - input: &impl ExecutionInput, - ) -> Result>, ExecutionError> { - // Check condition - let condition_fulfilled = match &query.selection { - Some(condition) => match condition.execute(input) { - Ok(DataValue::Bool(b)) => b, - Ok(_) => { - return Err(ExecutionError::GeneralError( - "Error evaluating WHERE statement (didn't evaluate to a boolean)" - .to_string(), - )); - } - Err(e) => return Err(e), - }, - None => true, - }; - - if condition_fulfilled { - struct NameAndData { - name: String, - data: Option>, - } - let mut fields = Vec::new(); - let mut is_subquery = false; - for (index, e) in query.projection.iter().enumerate() { - let expr_info = match e { - Expr::Datapoint { - name, data_type: _, .. - } => NameAndData { - name: name.clone(), - data: None, - }, - Expr::Alias { alias, expr } => { - match expr.as_ref() { - Expr::Subquery { index } => { - is_subquery = true; - match CompiledQuery::execute_internal( - &query.subquery[*index as usize], - input, - ) { - Ok(f) => match f { - None => NameAndData { - name: alias.clone(), - data: None, - }, - Some(vec) => NameAndData { - name: alias.clone(), - data: Some(vec), - }, - }, - Err(_) => { - // Don't be rude and just return None - NameAndData { - name: alias.clone(), - data: None, - } - } - } - } - _ => NameAndData { - name: alias.clone(), - data: None, - }, - } - } - Expr::Subquery { index } => { - is_subquery = true; - match CompiledQuery::execute_internal( - &query.subquery[*index as usize], - input, - ) { - Ok(f) => match f { - None => NameAndData { - name: format!("subquery_{index}"), - data: None, - }, - Some(vec) => NameAndData { - name: format!("subquery_{index}"), - data: Some(vec), - }, - }, - Err(_) => { - // Don't be rude and just return None - NameAndData { - name: format!("subquery_{index}"), - data: None, - } - } - } - } - _ => NameAndData { - name: format!("field_{index}"), - data: None, - }, - }; - - match expr_info.data { - None => match e.execute(input) { - Ok(value) => { - if !is_subquery { - fields.push((expr_info.name, value)) - } - } - Err(e) => return Err(e), - }, - Some(mut vec) => fields.append(&mut vec), - } - } - if !fields.is_empty() { - Ok(Some(fields)) - } else { - Ok(None) - } - } else { - // Successful execution, but condition wasn't met - Ok(None) - } - } - pub fn execute( - &self, - input: &impl ExecutionInput, - ) -> Result>, ExecutionError> { - CompiledQuery::execute_internal(self, input) - } -} - -impl Expr { - pub fn execute(&self, input: &impl ExecutionInput) -> Result { - match &self { - Expr::Datapoint { - name, - data_type: _, - lag, - } => { - let field = input.lookup(name); - if *lag { - Ok(field.lag_value.clone()) - } else { - Ok(field.value.clone()) - } - } - Expr::Alias { expr, .. } => expr.execute(input), - Expr::BinaryOperation { - left, - operator, - right, - } => execute_binary_operation(left, operator, right, input), - Expr::UnaryOperation { expr, operator } => { - execute_unary_operation(expr, operator, input) - } - Expr::ResolvedLiteral { - value, - data_type: _, - } => Ok(value.clone()), - Expr::Between { - expr, - negated, - low, - high, - } => execute_between_operation(expr, *negated, low, high, input), - Expr::Cast { - expr: _, - data_type: _, - } => todo!(), - Expr::UnresolvedLiteral { raw: _ } => { - debug_assert!( - false, - "Unresolved literal should result in compilation error" - ); - Err(ExecutionError::TypeError( - "Unresolved literal found while executing query".to_string(), - )) - } - Expr::Subquery { index } => Ok(DataValue::Uint32(*index)), - } - } -} - -fn execute_binary_operation( - left: &Expr, - operator: &Operator, - right: &Expr, - input: &impl ExecutionInput, -) -> Result { - let left_value = left.execute(input)?; - let right_value = right.execute(input)?; - - match operator { - Operator::Or => match (&left_value, &right_value) { - (DataValue::Bool(left), DataValue::Bool(right)) => Ok(DataValue::Bool(*left || *right)), - _ => Err(ExecutionError::TypeError(format!( - "OR is only possible with boolean expressions, tried \"{left_value:?} OR {right_value:?}\"" - ))), - }, - Operator::And => match (&left_value, &right_value) { - (DataValue::Bool(left), DataValue::Bool(right)) => Ok(DataValue::Bool(*left && *right)), - _ => Err(ExecutionError::TypeError(format!( - "AND is only possible with boolean expressions, tried \"{left_value:?} AND {right_value:?}\"" - ))), - }, - Operator::Eq => match left_value.equals(&right_value) { - Ok(equals) => Ok(DataValue::Bool(equals)), - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} = {right_value:?} isn't supported" - ))), - }, - Operator::NotEq => match left_value.equals(&right_value) { - Ok(equals) => Ok(DataValue::Bool(!equals)), // Negate equals - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} != {right_value:?} isn't supported" - ))), - }, - Operator::Gt => match left_value.greater_than(&right_value) { - Ok(greater_than) => Ok(DataValue::Bool(greater_than)), - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} > {right_value:?} isn't supported" - ))), - }, - Operator::Ge => match left_value.greater_than(&right_value) { - Ok(greater_than) => { - if greater_than { - Ok(DataValue::Bool(greater_than)) - } else { - match left_value.equals(&right_value) { - Ok(equals) => Ok(DataValue::Bool(equals)), - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} >= {right_value:?} isn't supported" - ))), - } - } - } - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} >= {right_value:?} isn't supported" - ))), - }, - Operator::Lt => match left_value.less_than(&right_value) { - Ok(less_than) => Ok(DataValue::Bool(less_than)), - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} < {right_value:?} isn't supported" - ))), - }, - Operator::Le => match left_value.less_than(&right_value) { - Ok(less_than) => { - if less_than { - Ok(DataValue::Bool(less_than)) - } else { - match left_value.equals(&right_value) { - Ok(equals) => Ok(DataValue::Bool(equals)), - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} <= {right_value:?} isn't supported" - ))), - } - } - } - Err(_) => Err(ExecutionError::CastError(format!( - "comparison {left_value:?} <= {right_value:?} isn't supported" - ))), - }, - } -} - -fn execute_unary_operation( - expr: &Expr, - operator: &UnaryOperator, - fields: &impl ExecutionInput, -) -> Result { - match operator { - UnaryOperator::Not => match expr.execute(fields) { - Ok(DataValue::Bool(b)) => Ok(DataValue::Bool(!b)), - Ok(_) => Err(ExecutionError::TypeError( - "negation of non boolean expression isn't supported".to_string(), - )), - Err(e) => Err(e), - }, - } -} - -fn execute_between_operation( - expr: &Expr, - negated: bool, - low: &Expr, - high: &Expr, - input: &impl ExecutionInput, -) -> Result { - match execute_binary_operation(expr, &Operator::Ge, low, input) { - Ok(DataValue::Bool(low_cond)) => match low_cond { - true => { - if negated { - return Ok(DataValue::Bool(false)); - } - } - false => { - if !negated { - return Ok(DataValue::Bool(false)); - } - } - }, - Ok(data_value) => { - return Err(ExecutionError::TypeError(format!( - "comparison BETWEEN {data_value:?} AND ... not supported" - ))) - } - Err(e) => return Err(e), - }; - - match execute_binary_operation(expr, &Operator::Le, high, input) { - Ok(DataValue::Bool(high_cond)) => match high_cond { - true => { - if negated { - return Ok(DataValue::Bool(false)); - } - } - false => { - if !negated { - return Ok(DataValue::Bool(false)); - } - } - }, - Ok(data_value) => { - return Err(ExecutionError::TypeError(format!( - "comparison BETWEEN ... AND {data_value:?} not supported" - ))) - } - Err(e) => return Err(e), - }; - Ok(DataValue::Bool(true)) -} - -impl ExecutionInputImpl { - pub fn new() -> Self { - Self { - fields: Default::default(), - } - } - - pub fn add(&mut self, name: String, value: ExecutionInputImplData) { - self.fields.insert(name, value); - } -} - -impl Default for ExecutionInputImpl { - fn default() -> Self { - Self::new() - } -} - -impl ExecutionInput for ExecutionInputImpl { - fn lookup(&self, field: &str) -> &ExecutionInputImplData { - match self.fields.get(field) { - Some(value) => value, - None => &ExecutionInputImplData { - value: DataValue::NotAvailable, - lag_value: DataValue::NotAvailable, - }, - } - } - - fn get_fields(&self) -> &HashMap { - &self.fields - } -} - -#[cfg(test)] -use super::{CompilationError, CompilationInput}; -#[cfg(test)] -use crate::query::compiler; -#[cfg(test)] -use crate::types::DataType; - -#[cfg(test)] -struct TestCompilationInput {} - -#[cfg(test)] -impl CompilationInput for TestCompilationInput { - fn get_datapoint_type(&self, field: &str) -> Result { - match field { - "Vehicle.Cabin.Seat.Row1.Pos1.Position" => Ok(DataType::Int32), - "Vehicle.Cabin.Seat.Row1.Pos2.Position" => Ok(DataType::Int32), - "Vehicle.Datapoint1" => Ok(DataType::Int32), - "Vehicle.Datapoint2" => Ok(DataType::Bool), - "Vehicle.ADAS.ABS.IsActive" => Ok(DataType::Bool), - _ => Err(CompilationError::UnknownField(field.to_owned())), - } - } -} - -#[cfg(test)] -fn assert_expected(res: Option>, expected: &[(String, DataValue)]) { - assert!(res.is_some()); - if let Some(fields) = &res { - assert_eq!(fields.len(), expected.len()); - for (i, (name, value)) in fields.iter().enumerate() { - assert_eq!(name, &expected[i].0); - assert_eq!(value, &expected[i].1); - println!("{name}: {value:?}") - } - } -} - -#[test] -fn executor_test() { - let sql = " - SELECT - Vehicle.Cabin.Seat.Row1.Pos1.Position, - Vehicle.Cabin.Seat.Row1.Pos2.Position - WHERE - Vehicle.Datapoint1 > 50 - AND - Vehicle.Datapoint2 = true - "; - - let test_compilation_input = TestCompilationInput {}; - let compiled_query = compiler::compile(sql, &test_compilation_input).unwrap(); - - assert!(&compiled_query - .input_spec - .contains("Vehicle.Cabin.Seat.Row1.Pos1.Position")); - assert!(&compiled_query - .input_spec - .contains("Vehicle.Cabin.Seat.Row1.Pos2.Position")); - assert!(&compiled_query.input_spec.contains("Vehicle.Datapoint1")); - assert!(&compiled_query.input_spec.contains("Vehicle.Datapoint2")); - - println!("EXECUTE"); - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::NotAvailable, - }, - ); - execution_input1.add( - "Vehicle.Datapoint1".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(61), - lag_value: DataValue::NotAvailable, - }, - ); - execution_input1.add( - "Vehicle.Datapoint2".to_string(), - ExecutionInputImplData { - value: DataValue::Bool(true), - lag_value: DataValue::NotAvailable, - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - - println!("RESULT: "); - let expected = vec![ - ( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_owned(), - DataValue::Int32(230), - ), - ( - "Vehicle.Cabin.Seat.Row1.Pos2.Position".to_owned(), - DataValue::NotAvailable, - ), - ]; - assert_expected(res, &expected); - - println!("EXECUTE"); - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::NotAvailable, - }, - ); - execution_input1.add( - "Vehicle.Datapoint1".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(40), - lag_value: DataValue::NotAvailable, - }, - ); - execution_input1.add( - "Vehicle.Datapoint2".to_string(), - ExecutionInputImplData { - value: DataValue::Bool(true), - lag_value: DataValue::NotAvailable, - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - - assert!(res.is_none()); -} - -#[test] -fn executor_lag_test() { - let sql = " - SELECT - Vehicle.Cabin.Seat.Row1.Pos1.Position, - LAG(Vehicle.Cabin.Seat.Row1.Pos1.Position) as previousCabinSeatRow1PosPosition - "; - - let test_compilation_input = TestCompilationInput {}; - let compiled_query = compiler::compile(sql, &test_compilation_input).unwrap(); - if let Some(Expr::Alias { alias, expr }) = compiled_query.projection.get(1) { - assert_eq!(alias, "previousCabinSeatRow1PosPosition"); - if let Expr::Datapoint { lag, .. } = **expr { - assert!(lag); - } - } - - println!("EXECUTE"); - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::Int32(231), - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - assert!(res.is_some()); - let expected = vec![ - ( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_owned(), - DataValue::Int32(230), - ), - ( - "previousCabinSeatRow1PosPosition".to_owned(), - DataValue::Int32(231), - ), - ]; - assert_expected(res, &expected); -} - -#[test] -fn executor_lag_subquery_test() { - let sql = " - SELECT - (SELECT Vehicle.Cabin.Seat.Row1.Pos1.Position), - (SELECT LAG(Vehicle.Cabin.Seat.Row1.Pos1.Position) as previousCabinSeatRow1PosPosition) - "; - let test_compilation_input = TestCompilationInput {}; - let compiled_query = compiler::compile(sql, &test_compilation_input).unwrap(); - assert_eq!(compiled_query.subquery.len(), 2); - if let Some(subquery) = compiled_query.subquery.first() { - assert!(subquery - .input_spec - .contains("Vehicle.Cabin.Seat.Row1.Pos1.Position")); - } - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::Int32(231), - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - assert!(res.is_some()); - let expected = vec![ - ( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_owned(), - DataValue::Int32(230), - ), - ( - "previousCabinSeatRow1PosPosition".to_owned(), - DataValue::Int32(231), - ), - ]; - assert_expected(res, &expected); -} - -#[test] -fn executor_where_lag_subquery_test() { - let sql = " - SELECT - (SELECT Vehicle.Cabin.Seat.Row1.Pos1.Position - WHERE - LAG(Vehicle.Cabin.Seat.Row1.Pos1.Position) <> Vehicle.Cabin.Seat.Row1.Pos1.Position - ) - "; - let test_compilation_input = TestCompilationInput {}; - let compiled_query = compiler::compile(sql, &test_compilation_input).unwrap(); - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::NotAvailable, - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - assert!(res.is_some()); - let expected = vec![( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_owned(), - DataValue::Int32(230), - )]; - assert_expected(res, &expected); - - let mut execution_input1 = ExecutionInputImpl::new(); - execution_input1.add( - "Vehicle.Cabin.Seat.Row1.Pos1.Position".to_string(), - ExecutionInputImplData { - value: DataValue::Int32(230), - lag_value: DataValue::Int32(230), - }, - ); - let res = compiled_query.execute(&execution_input1).unwrap(); - assert!(res.is_none()); -} diff --git a/kuksa_databroker/databroker/src/query/expr.rs b/kuksa_databroker/databroker/src/query/expr.rs deleted file mode 100644 index 1e97028ee..000000000 --- a/kuksa_databroker/databroker/src/query/expr.rs +++ /dev/null @@ -1,110 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use crate::types::{DataType, DataValue}; - -#[derive(Debug, Clone)] -pub enum Expr { - Datapoint { - name: String, - data_type: DataType, - lag: bool, - }, - Alias { - expr: Box, - alias: String, - }, - Cast { - expr: Box, - data_type: DataType, - }, - UnresolvedLiteral { - raw: String, - }, - ResolvedLiteral { - value: DataValue, - data_type: DataType, - }, - BinaryOperation { - left: Box, - operator: Operator, - right: Box, - }, - UnaryOperation { - expr: Box, - operator: UnaryOperator, - }, - Subquery { - index: u32, - }, - Between { - expr: Box, - negated: bool, - low: Box, - high: Box, - }, -} - -#[derive(Debug, Clone)] -pub enum Operator { - And, - Or, - Eq, - NotEq, - Gt, - Ge, - Lt, - Le, -} - -#[derive(Debug, Clone)] -pub enum UnaryOperator { - Not, -} - -pub enum UnresolvedLiteral { - Number(String), - Error, -} - -impl Expr { - pub fn get_type(&self) -> Result { - match self { - Expr::Datapoint { - name: _, data_type, .. - } => Ok(data_type.clone()), - Expr::Alias { expr, alias: _ } => expr.get_type(), - Expr::Cast { expr: _, data_type } => Ok(data_type.clone()), - Expr::UnresolvedLiteral { raw } => Err(UnresolvedLiteral::Number(raw.clone())), - Expr::Subquery { index: _ } => Ok(DataType::Uint32), - Expr::ResolvedLiteral { - value: _, - data_type, - } => Ok(data_type.clone()), - Expr::BinaryOperation { - left: _, - operator: _, - right: _, - } => Ok(DataType::Bool), - Expr::UnaryOperation { expr: _, operator } => match operator { - UnaryOperator::Not => Ok(DataType::Bool), - }, - Expr::Between { - expr: _, - negated: _, - low: _, - high: _, - } => Ok(DataType::Bool), - } - } -} diff --git a/kuksa_databroker/databroker/src/query/mod.rs b/kuksa_databroker/databroker/src/query/mod.rs deleted file mode 100644 index 137fe0c91..000000000 --- a/kuksa_databroker/databroker/src/query/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -mod compiler; -mod executor; -mod expr; - -pub use compiler::compile; -pub use compiler::{CompilationError, CompilationInput, CompiledQuery}; - -pub use executor::{ExecutionError, ExecutionInput}; - -// Example trait implementations -pub use compiler::CompilationInputImpl; -pub use executor::ExecutionInputImpl; diff --git a/kuksa_databroker/databroker/src/types.rs b/kuksa_databroker/databroker/src/types.rs deleted file mode 100644 index 6d9241fd9..000000000 --- a/kuksa_databroker/databroker/src/types.rs +++ /dev/null @@ -1,1142 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::convert::TryFrom; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DataType { - String, - Bool, - Int8, - Int16, - Int32, - Int64, - Uint8, - Uint16, - Uint32, - Uint64, - Float, - Double, - StringArray, - BoolArray, - Int8Array, - Int16Array, - Int32Array, - Int64Array, - Uint8Array, - Uint16Array, - Uint32Array, - Uint64Array, - FloatArray, - DoubleArray, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum EntryType { - Sensor, - Attribute, - Actuator, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ChangeType { - Static, - OnChange, - Continuous, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum DataValue { - NotAvailable, - Bool(bool), - String(String), - Int32(i32), - Int64(i64), - Uint32(u32), - Uint64(u64), - Float(f32), - Double(f64), - BoolArray(Vec), - StringArray(Vec), - Int32Array(Vec), - Int64Array(Vec), - Uint32Array(Vec), - Uint64Array(Vec), - FloatArray(Vec), - DoubleArray(Vec), -} - -#[derive(Debug)] -pub struct CastError {} - -impl DataValue { - pub fn greater_than(&self, other: &DataValue) -> Result { - match (&self, other) { - (DataValue::Int32(value), DataValue::Int32(other_value)) => Ok(value > other_value), - (DataValue::Int32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) > *other_value) - } - (DataValue::Int32(value), DataValue::Uint32(other_value)) => { - Ok(i64::from(*value) > i64::from(*other_value)) - } - (DataValue::Int32(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(false) // Negative value cannot be greater than unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value > *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int32(value), DataValue::Float(other_value)) => { - Ok(f64::from(*value) > f64::from(*other_value)) - } - (DataValue::Int32(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) > *other_value) - } - (DataValue::Int64(value), DataValue::Int32(other_value)) => { - Ok(*value > i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Int64(other_value)) => Ok(value > other_value), - (DataValue::Int64(value), DataValue::Uint32(other_value)) => { - Ok(*value > i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(false) // Negative value cannot be greater than unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value > *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int64(value), DataValue::Float(other_value)) => match i32::try_from(*value) - { - Ok(value) => Ok(f64::from(value) > f64::from(*other_value)), - Err(_) => Err(CastError {}), - }, - (DataValue::Int64(value), DataValue::Double(other_value)) => { - match i32::try_from(*value) { - Ok(value) => Ok(f64::from(value) > *other_value), - Err(_) => Err(CastError {}), - } - } - (DataValue::Uint32(value), DataValue::Int32(other_value)) => { - Ok(i64::from(*value) > i64::from(*other_value)) - } - (DataValue::Uint32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) > *other_value) - } - (DataValue::Uint32(value), DataValue::Uint32(other_value)) => Ok(value > other_value), - (DataValue::Uint32(value), DataValue::Uint64(other_value)) => { - Ok(u64::from(*value) > *other_value) - } - (DataValue::Uint32(value), DataValue::Float(other_value)) => { - Ok(f64::from(*value) > f64::from(*other_value)) - } - (DataValue::Uint32(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) > *other_value) - } - (DataValue::Uint64(value), DataValue::Int32(other_value)) => { - if *other_value < 0 { - Ok(true) // Unsigned must be greater than a negative - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value > other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Int64(other_value)) => { - if *other_value < 0 { - Ok(true) // Unsigned must be greater than a negative - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value > other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Uint32(other_value)) => { - Ok(*value > u64::from(*other_value)) - } - (DataValue::Uint64(value), DataValue::Uint64(other_value)) => Ok(value > other_value), - (DataValue::Uint64(value), DataValue::Float(other_value)) => { - match u32::try_from(*value) { - Ok(value) => Ok(f64::from(value) > f64::from(*other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Uint64(value), DataValue::Double(other_value)) => { - match u32::try_from(*value) { - Ok(value) => Ok(f64::from(value) > *other_value), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Int32(other_value)) => { - Ok(f64::from(*value) > f64::from(*other_value)) - } - (DataValue::Float(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => Ok(f64::from(*value) > f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Uint32(other_value)) => { - Ok(f64::from(*value) > f64::from(*other_value)) - } - (DataValue::Float(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => Ok(f64::from(*value) > f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Float(other_value)) => Ok(value > other_value), - (DataValue::Float(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) > *other_value) - } - (DataValue::Double(value), DataValue::Int32(other_value)) => { - Ok(*value > f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => Ok(*value > f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Uint32(other_value)) => { - Ok(*value > f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => Ok(*value > f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Float(other_value)) => { - Ok(*value > f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Double(other_value)) => Ok(value > other_value), - _ => Err(CastError {}), - } - } - - pub fn less_than(&self, other: &DataValue) -> Result { - match (&self, other) { - (DataValue::Int32(value), DataValue::Int32(other_value)) => Ok(value < other_value), - (DataValue::Int32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) < *other_value) - } - (DataValue::Int32(value), DataValue::Uint32(other_value)) => { - Ok(i64::from(*value) < i64::from(*other_value)) - } - (DataValue::Int32(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(true) // Negative value must be less than unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value < *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int32(value), DataValue::Float(other_value)) => { - Ok(f64::from(*value) < f64::from(*other_value)) - } - (DataValue::Int32(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) < *other_value) - } - - (DataValue::Int64(value), DataValue::Int32(other_value)) => { - Ok(*value < i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Int64(other_value)) => Ok(value < other_value), - (DataValue::Int64(value), DataValue::Uint32(other_value)) => { - Ok(*value < i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(true) // Negative value must be less than unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value < *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int64(value), DataValue::Float(other_value)) => match i32::try_from(*value) - { - Ok(value) => Ok(f64::from(value) < f64::from(*other_value)), - Err(_) => Err(CastError {}), - }, - (DataValue::Int64(value), DataValue::Double(other_value)) => { - match i32::try_from(*value) { - Ok(value) => Ok(f64::from(value) < *other_value), - Err(_) => Err(CastError {}), - } - } - - (DataValue::Uint32(value), DataValue::Int32(other_value)) => { - Ok(i64::from(*value) < i64::from(*other_value)) - } - (DataValue::Uint32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) < *other_value) - } - (DataValue::Uint32(value), DataValue::Uint32(other_value)) => Ok(value < other_value), - (DataValue::Uint32(value), DataValue::Uint64(other_value)) => { - Ok(u64::from(*value) < *other_value) - } - (DataValue::Uint32(value), DataValue::Float(other_value)) => { - Ok(f64::from(*value) < f64::from(*other_value)) - } - (DataValue::Uint32(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) < *other_value) - } - (DataValue::Uint64(value), DataValue::Int32(other_value)) => { - if *other_value < 0 { - Ok(false) // Unsigned cannot be less than a negative value - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value < other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Int64(other_value)) => { - if *other_value < 0 { - Ok(false) // Unsigned cannot be less than a negative value - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value < other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Uint32(other_value)) => { - Ok(*value < u64::from(*other_value)) - } - (DataValue::Uint64(value), DataValue::Uint64(other_value)) => Ok(value < other_value), - (DataValue::Uint64(value), DataValue::Float(other_value)) => { - match u32::try_from(*value) { - Ok(value) => Ok(f64::from(value) < f64::from(*other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Uint64(value), DataValue::Double(other_value)) => { - match u32::try_from(*value) { - Ok(value) => Ok(f64::from(value) < *other_value), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Int32(other_value)) => { - Ok(f64::from(*value) < f64::from(*other_value)) - } - (DataValue::Float(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => Ok(f64::from(*value) < f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Uint32(other_value)) => { - Ok(f64::from(*value) < f64::from(*other_value)) - } - (DataValue::Float(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => Ok(f64::from(*value) < f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Float(other_value)) => Ok(value < other_value), - (DataValue::Float(value), DataValue::Double(other_value)) => { - Ok(f64::from(*value) < *other_value) - } - (DataValue::Double(value), DataValue::Int32(other_value)) => { - Ok(*value < f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => Ok(*value < f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Uint32(other_value)) => { - Ok(*value < f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => Ok(*value < f64::from(other_value)), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Float(other_value)) => { - Ok(*value < f64::from(*other_value)) - } - (DataValue::Double(value), DataValue::Double(other_value)) => Ok(value < other_value), - _ => Err(CastError {}), - } - } - - pub fn equals(&self, other: &DataValue) -> Result { - match (&self, other) { - (DataValue::Bool(value), DataValue::Bool(other_value)) => Ok(value == other_value), - (DataValue::String(value), DataValue::String(other_value)) => Ok(value == other_value), - (DataValue::Int32(value), DataValue::Int32(other_value)) => Ok(value == other_value), - (DataValue::Int32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) == *other_value) - } - (DataValue::Int32(value), DataValue::Uint32(other_value)) => { - Ok(i64::from(*value) == i64::from(*other_value)) - } - (DataValue::Int32(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(false) // Negative value cannot be equal to unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value == *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int32(value), DataValue::Float(other_value)) => { - Ok((f64::from(*value) - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Int32(value), DataValue::Double(other_value)) => { - Ok((f64::from(*value) - *other_value).abs() < f64::EPSILON) - } - (DataValue::Int64(value), DataValue::Int32(other_value)) => { - Ok(*value == i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Int64(other_value)) => Ok(value == other_value), - (DataValue::Int64(value), DataValue::Uint32(other_value)) => { - Ok(*value == i64::from(*other_value)) - } - (DataValue::Int64(value), DataValue::Uint64(other_value)) => { - if *value < 0 { - Ok(false) // Negative value cannot be equal to unsigned - } else { - match u64::try_from(*value) { - Ok(value) => Ok(value == *other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Int64(value), DataValue::Float(other_value)) => match i32::try_from(*value) - { - Ok(value) => Ok((f64::from(value) - f64::from(*other_value)).abs() < f64::EPSILON), - Err(_) => Err(CastError {}), - }, - (DataValue::Int64(value), DataValue::Double(other_value)) => { - match i32::try_from(*value) { - Ok(value) => Ok((f64::from(value) - *other_value).abs() < f64::EPSILON), - Err(_) => Err(CastError {}), - } - } - (DataValue::Uint32(value), DataValue::Int32(other_value)) => { - Ok(i64::from(*value) == i64::from(*other_value)) - } - (DataValue::Uint32(value), DataValue::Int64(other_value)) => { - Ok(i64::from(*value) == *other_value) - } - (DataValue::Uint32(value), DataValue::Uint32(other_value)) => Ok(value == other_value), - (DataValue::Uint32(value), DataValue::Uint64(other_value)) => { - Ok(u64::from(*value) == *other_value) - } - (DataValue::Uint32(value), DataValue::Float(other_value)) => { - Ok((f64::from(*value) - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Uint32(value), DataValue::Double(other_value)) => { - Ok((f64::from(*value) - *other_value).abs() < f64::EPSILON) - } - (DataValue::Uint64(value), DataValue::Int32(other_value)) => { - if *other_value < 0 { - Ok(false) // Unsigned cannot be equal to negative value - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value == other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Int64(other_value)) => { - if *other_value < 0 { - Ok(false) // Unsigned cannot be equal to negative value - } else { - match u64::try_from(*other_value) { - Ok(other_value) => Ok(*value == other_value), - Err(_) => Err(CastError {}), - } - } - } - (DataValue::Uint64(value), DataValue::Uint32(other_value)) => { - Ok(*value == u64::from(*other_value)) - } - (DataValue::Uint64(value), DataValue::Uint64(other_value)) => Ok(value == other_value), - (DataValue::Uint64(value), DataValue::Float(other_value)) => { - match u32::try_from(*value) { - Ok(value) => { - Ok((f64::from(value) - f64::from(*other_value)).abs() < f64::EPSILON) - } - Err(_) => Err(CastError {}), - } - } - (DataValue::Uint64(value), DataValue::Double(other_value)) => { - match u32::try_from(*value) { - Ok(value) => Ok((f64::from(value) - *other_value).abs() < f64::EPSILON), - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Int32(other_value)) => { - Ok((f64::from(*value) - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Float(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => { - Ok((f64::from(*value) - f64::from(other_value)).abs() < f64::EPSILON) - } - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Uint32(other_value)) => { - Ok((f64::from(*value) - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Float(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => { - Ok((f64::from(*value) - f64::from(other_value)).abs() < f64::EPSILON) - } - Err(_) => Err(CastError {}), - } - } - (DataValue::Float(value), DataValue::Float(other_value)) => { - // TODO: Implement better floating point comparison - Ok((value - other_value).abs() < f32::EPSILON) - } - (DataValue::Float(value), DataValue::Double(other_value)) => { - // TODO: Implement better floating point comparison - Ok((f64::from(*value) - *other_value).abs() < f64::EPSILON) - } - (DataValue::Double(value), DataValue::Int32(other_value)) => { - Ok((*value - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Double(value), DataValue::Int64(other_value)) => { - match i32::try_from(*other_value) { - Ok(other_value) => Ok((*value - f64::from(other_value)).abs() < f64::EPSILON), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Uint32(other_value)) => { - Ok((*value - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Double(value), DataValue::Uint64(other_value)) => { - match u32::try_from(*other_value) { - Ok(other_value) => Ok((*value - f64::from(other_value)).abs() < f64::EPSILON), - Err(_) => Err(CastError {}), - } - } - (DataValue::Double(value), DataValue::Float(other_value)) => { - // TODO: Implement better floating point comparison - Ok((*value - f64::from(*other_value)).abs() < f64::EPSILON) - } - (DataValue::Double(value), DataValue::Double(other_value)) => { - // TODO: Implement better floating point comparison - Ok((value - other_value).abs() < f64::EPSILON) - } - (DataValue::NotAvailable, DataValue::Int32(..)) - | (DataValue::NotAvailable, DataValue::Int64(..)) - | (DataValue::NotAvailable, DataValue::Uint32(..)) - | (DataValue::NotAvailable, DataValue::Uint64(..)) - | (DataValue::NotAvailable, DataValue::Float(..)) - | (DataValue::NotAvailable, DataValue::Double(..)) => Ok(false), - (DataValue::Int32(..), DataValue::NotAvailable) - | (DataValue::Int64(..), DataValue::NotAvailable) - | (DataValue::Uint32(..), DataValue::NotAvailable) - | (DataValue::Uint64(..), DataValue::NotAvailable) - | (DataValue::Float(..), DataValue::NotAvailable) - | (DataValue::Double(..), DataValue::NotAvailable) => Ok(false), - _ => Err(CastError {}), - } - } -} - -#[derive(Debug)] -pub struct ExecutionInputImplData { - pub value: DataValue, - pub lag_value: DataValue, -} - -#[test] -fn test_string_greater_than() { - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Bool(false)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::String("string2".to_owned())) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Int32(100)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Int64(100)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Uint32(100)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Uint64(100)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Float(100.0)) - .is_err()); - assert!(DataValue::String("string".to_owned()) - .greater_than(&DataValue::Double(100.0)) - .is_err()); -} - -#[test] -fn test_not_available_greater_than() { - assert!(DataValue::NotAvailable - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Bool(false)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Int32(100)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Int64(100)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Uint32(100)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Uint64(100)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Float(100.0)) - .is_err()); - assert!(DataValue::NotAvailable - .greater_than(&DataValue::Double(100.0)) - .is_err()); -} - -#[test] -fn test_bool_greater_than() { - assert!(DataValue::Bool(false) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Bool(false)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Int32(100)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Int64(100)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Uint32(100)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Uint64(100)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Float(100.0)) - .is_err()); - assert!(DataValue::Bool(false) - .greater_than(&DataValue::Double(100.0)) - .is_err()); -} - -#[test] -fn test_int32_greater_than() { - // Comparison not possible - // - assert!(DataValue::Int32(5000) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Int32(5000) - .greater_than(&DataValue::Bool(true)) - .is_err()); - assert!(DataValue::Int32(5000) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - - // Should be greater than - // - assert!(matches!( - DataValue::Int32(5000).greater_than(&DataValue::Int32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(5000).greater_than(&DataValue::Int32(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(-4000).greater_than(&DataValue::Int32(-5000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(5000).greater_than(&DataValue::Int64(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(5000).greater_than(&DataValue::Int64(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(5000).greater_than(&DataValue::Uint32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(-4000).greater_than(&DataValue::Int64(-5000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(i32::MAX) - .greater_than(&DataValue::Uint64(u64::try_from(i32::MAX - 1).unwrap())), - Ok(true) - )); - assert!(matches!( - DataValue::Int32(30).greater_than(&DataValue::Uint64(20)), - Ok(true) - )); - - // Should not be greater than - // - - assert!(matches!( - DataValue::Int32(-5000).greater_than(&DataValue::Uint32(4000)), - Ok(false) - )); - assert!(matches!( - DataValue::Int32(4000).greater_than(&DataValue::Uint32(5000)), - Ok(false) - )); - assert!(matches!( - DataValue::Int32(20).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Int32(10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Int32(-10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Int32(-10).greater_than(&DataValue::Uint64(u64::MAX)), - Ok(false) - )); -} - -#[test] -fn test_int64_greater_than() { - // Comparison not possible - // - - assert!(DataValue::Int64(5000) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Int64(5000) - .greater_than(&DataValue::Bool(true)) - .is_err()); - assert!(DataValue::Int64(5000) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - - // Should be greater than - // - - assert!(matches!( - DataValue::Int64(5000).greater_than(&DataValue::Int32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(5000).greater_than(&DataValue::Int32(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(-4000).greater_than(&DataValue::Int32(-5000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(5000).greater_than(&DataValue::Int64(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(5000).greater_than(&DataValue::Int64(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(5000).greater_than(&DataValue::Uint32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(-4000).greater_than(&DataValue::Int64(-5000)), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(i64::from(i32::MAX)) - .greater_than(&DataValue::Uint64(u64::try_from(i32::MAX - 1).unwrap())), - Ok(true) - )); - assert!(matches!( - DataValue::Int64(30).greater_than(&DataValue::Uint64(20)), - Ok(true) - )); - - // Should not be greater than - // - - assert!(matches!( - DataValue::Int64(-10).greater_than(&DataValue::Uint64(u64::MAX)), - Ok(false) - )); - assert!(matches!( - DataValue::Int64(-5000).greater_than(&DataValue::Uint32(4000)), - Ok(false) - )); - assert!(matches!( - DataValue::Int64(4000).greater_than(&DataValue::Uint32(5000)), - Ok(false) - )); - assert!(matches!( - DataValue::Int64(20).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Int64(10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Int64(-10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); -} - -#[test] -fn test_uint32_greater_than() { - // Comparison not possible - // - - assert!(DataValue::Uint32(5000) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Uint32(5000) - .greater_than(&DataValue::Bool(true)) - .is_err()); - assert!(DataValue::Uint32(5000) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - - // Should be greater than - // - - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Int32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Int32(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Int64(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Int64(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Float(4000.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Double(-4000.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(5000).greater_than(&DataValue::Uint32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(u32::MAX).greater_than(&DataValue::Int32(-5000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(u32::MAX).greater_than(&DataValue::Int64(i64::MIN)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint32(30).greater_than(&DataValue::Uint64(20)), - Ok(true) - )); - - // Should not be greater than - // - - assert!(matches!( - DataValue::Uint32(4000).greater_than(&DataValue::Int32(5000)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint32(4000).greater_than(&DataValue::Uint32(5000)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint32(20).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint32(10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint32(20).greater_than(&DataValue::Float(20.0)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint32(10).greater_than(&DataValue::Double(20.0)), - Ok(false) - )); -} - -#[test] -fn test_uint64_greater_than() { - // Comparison not possible - // - - assert!(DataValue::Uint64(5000) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Uint64(5000) - .greater_than(&DataValue::Bool(true)) - .is_err()); - assert!(DataValue::Uint64(5000) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - - // Should be greater than - // - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Int32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Int32(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Int64(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Int64(-4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Float(4000.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Double(-4000.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(5000).greater_than(&DataValue::Uint32(4000)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(u64::MAX).greater_than(&DataValue::Int64(i64::MAX - 1)), - Ok(true) - )); - assert!(matches!( - DataValue::Uint64(30).greater_than(&DataValue::Uint64(20)), - Ok(true) - )); - - // Should not be greater than - // - - assert!(matches!( - DataValue::Uint64(4000).greater_than(&DataValue::Uint32(5000)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint64(20).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint64(10).greater_than(&DataValue::Uint64(20)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint64(20).greater_than(&DataValue::Float(20.0)), - Ok(false) - )); - assert!(matches!( - DataValue::Uint64(10).greater_than(&DataValue::Double(20.0)), - Ok(false) - )); -} - -#[test] -fn test_float_greater_than() {} - -#[test] -fn test_double_greater_than() {} - -#[test] -fn test_int32_less_than() {} - -#[test] -fn test_int64_less_than() {} - -#[test] -fn test_uint32_less_than() {} - -#[test] -fn test_uint64_less_than() {} - -#[test] -fn test_float_less_than() {} - -#[test] -fn test_double_less_than() {} - -#[test] -fn test_float_equals() { - assert!(DataValue::Float(5000.0) - .greater_than(&DataValue::NotAvailable) - .is_err()); - assert!(DataValue::Float(5000.0) - .greater_than(&DataValue::Bool(true)) - .is_err()); - assert!(DataValue::Float(5000.0) - .greater_than(&DataValue::String("string".to_owned())) - .is_err()); - - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Int32(32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Int64(32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Uint32(32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Uint64(32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Float(32.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Double(32.0)), - Ok(true) - )); - - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Int32(-32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Int64(-32)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Uint32(32)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Uint64(32)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Float(-32.0)), - Ok(true) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Double(-32.0)), - Ok(true) - )); - - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Int32(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Int64(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Uint32(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Uint64(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Float(33.0)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(32.0).equals(&DataValue::Double(33.0)), - Ok(false) - )); - - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Int32(-33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Int64(-33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Uint32(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Uint64(33)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Float(-33.0)), - Ok(false) - )); - assert!(matches!( - DataValue::Float(-32.0).equals(&DataValue::Double(-33.0)), - Ok(false) - )); -} diff --git a/kuksa_databroker/databroker/src/viss/mod.rs b/kuksa_databroker/databroker/src/viss/mod.rs deleted file mode 100644 index 31a6e7d61..000000000 --- a/kuksa_databroker/databroker/src/viss/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -pub mod server; -pub mod v2; diff --git a/kuksa_databroker/databroker/src/viss/server.rs b/kuksa_databroker/databroker/src/viss/server.rs deleted file mode 100644 index 70ea80c3d..000000000 --- a/kuksa_databroker/databroker/src/viss/server.rs +++ /dev/null @@ -1,276 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use axum::{ - extract::ws::{CloseFrame, Message, WebSocket, WebSocketUpgrade}, - response::IntoResponse, - routing::get, - Router, -}; -use std::{borrow::Cow, net::SocketAddr}; - -use tracing::{debug, error, info, trace}; - -use futures::{channel::mpsc, Sink}; -use futures::{stream::StreamExt, Stream}; - -use crate::authorization::Authorization; -use crate::broker; - -use super::v2::{self, server::Viss}; - -#[derive(Clone)] -struct AppState { - broker: broker::DataBroker, - authorization: Authorization, -} - -pub async fn serve( - addr: impl Into, - broker: broker::DataBroker, - // #[cfg(feature = "tls")] server_tls: ServerTLS, - authorization: Authorization, - // signal: F -) -> Result<(), Box> { - let app = Router::new() - .route("/", get(handle_upgrade)) - .with_state(AppState { - broker, - authorization, - }); - - let addr = addr.into(); - let builder = axum::Server::try_bind(&addr).map_err(|err| { - error!("Failed to bind address {addr}: {err}"); - err - })?; - - info!("VISSv2 (websocket) service listening on {}", addr); - builder - .serve(app.into_make_service_with_connect_info::()) - .await - .map_err(|e| e.into()) -} - -// Handle upgrade request -async fn handle_upgrade( - ws: WebSocketUpgrade, - axum::extract::ConnectInfo(addr): axum::extract::ConnectInfo, - axum::extract::State(state): axum::extract::State, -) -> impl IntoResponse { - debug!("Received websocket upgrade request"); - ws.protocols(["VISSv2"]) - .on_upgrade(move |socket| handle_websocket(socket, addr, state.broker, state.authorization)) -} - -// Handle websocket (one per connection) -async fn handle_websocket( - socket: WebSocket, - addr: SocketAddr, - broker: broker::DataBroker, - authorization: Authorization, -) { - let valid_subprotocol = match socket.protocol() { - Some(subprotocol) => match subprotocol.to_str() { - Ok("VISSv2") => { - debug!("VISSv2 requested"); - true - } - Ok(_) | Err(_) => { - debug!("Unsupported websocket subprotocol"); - false - } - }, - None => { - debug!("Websocket subprotocol not specified, defaulting to VISSv2"); - true - } - }; - let mut socket = socket; - if !valid_subprotocol { - let _ = socket - .send(Message::Close(Some(CloseFrame { - code: axum::extract::ws::close_code::PROTOCOL, - reason: Cow::from("Unsupported websocket subprotocol"), - }))) - .await; - return; - } - - let (write, read) = socket.split(); - - handle_viss_v2(write, read, addr, broker, authorization).await; -} - -async fn handle_viss_v2( - write: W, - mut read: R, - client_addr: SocketAddr, - broker: broker::DataBroker, - authorization: Authorization, -) where - W: Sink + Unpin + Send + 'static, - >::Error: Send, - R: Stream> + Unpin + Send + 'static, -{ - // Create a multi producer / single consumer channel, where the - // single consumer will write to the socket. - let (sender, receiver) = mpsc::channel::(10); - - let server = v2::server::Server::new(broker, authorization); - let mut write_task = tokio::spawn(async move { - let _ = receiver.map(Ok).forward(write).await; - }); - - let mut read_task = tokio::spawn(async move { - while let Some(Ok(msg)) = read.next().await { - match msg { - Message::Text(msg) => { - debug!("Received request: {msg}"); - - // Handle it - let sender = sender.clone(); - let serialized_response = match parse_v2_msg(&msg) { - Ok(request) => { - match request { - v2::Request::Get(request) => match server.get(request).await { - Ok(response) => serialize(response), - Err(error_response) => serialize(error_response), - }, - v2::Request::Set(request) => match server.set(request).await { - Ok(response) => serialize(response), - Err(error_response) => serialize(error_response), - }, - v2::Request::Subscribe(request) => { - match server.subscribe(request).await { - Ok((response, stream)) => { - // Setup background stream - let mut background_sender = sender.clone(); - - tokio::spawn(async move { - let mut stream = stream; - while let Some(event) = stream.next().await { - let serialized_event = match event { - Ok(event) => serialize(event), - Err(error_event) => serialize(error_event), - }; - - if let Ok(text) = serialized_event { - debug!("Sending notification: {}", text); - if let Err(err) = background_sender - .try_send(Message::Text(text)) - { - debug!("Failed to send notification: {err}"); - if err.is_disconnected() { - break; - } - }; - } - } - }); - - // Return response - serialize(response) - } - Err(error_response) => serialize(error_response), - } - } - v2::Request::Unsubscribe(request) => { - match server.unsubscribe(request).await { - Ok(response) => serialize(response), - Err(error_response) => serialize(error_response), - } - } - } - } - Err(error_response) => serialize(error_response), - }; - - // Send it - if let Ok(text) = serialized_response { - debug!("Sending response: {}", text); - let mut sender = sender; - if let Err(err) = sender.try_send(Message::Text(text)) { - debug!("Failed to send response: {err}") - }; - } - } - Message::Binary(msg) => { - debug!( - "Received binary message from {} (ignoring it) len={}: {:?}", - client_addr, - msg.len(), - msg - ); - } - Message::Close(msg) => { - if let Some(close) = msg { - debug!( - "Received close connection request from {}: code = {}, reason: \"{}\"", - client_addr, close.code, close.reason - ); - } else { - debug!( - "Received close connection request from {}: (missing CloseFrame)", - client_addr - ); - } - break; - } - Message::Pong(msg) => { - trace!("Received pong message from {}: {:?}", client_addr, msg); - } - Message::Ping(msg) => { - // Handled automatically - trace!("Received ping message from {}: {:?}", client_addr, msg); - } - } - } - }); - - // If any one of the tasks exit, abort the other. - tokio::select! { - _ = (&mut read_task) => { - debug!("Read task completed, aborting write task."); - write_task.abort(); - } - _ = (&mut write_task) => { - debug!("Write task completed, aborting read task."); - read_task.abort(); - }, - } - info!("Websocket connection closed ({})", client_addr); -} - -fn parse_v2_msg(msg: &str) -> Result { - let request: v2::Request = - serde_json::from_str(msg).map_err(|_| { - match serde_json::from_str::(msg) { - Ok(request) => v2::GenericErrorResponse { - action: request.action, - request_id: request.request_id, - error: v2::Error::BadRequest { msg: None }, - }, - Err(_) => v2::GenericErrorResponse { - action: None, - request_id: None, - error: v2::Error::BadRequest { msg: None }, - }, - } - })?; - Ok(request) -} - -fn serialize(response: impl v2::Response) -> Result { - serde_json::to_string(&response) -} diff --git a/kuksa_databroker/databroker/src/viss/v2/conversions.rs b/kuksa_databroker/databroker/src/viss/v2/conversions.rs deleted file mode 100644 index a209cb6ad..000000000 --- a/kuksa_databroker/databroker/src/viss/v2/conversions.rs +++ /dev/null @@ -1,432 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::{convert::TryFrom, time::SystemTime}; - -use crate::broker; - -use super::types::{ - ActuatorEntry, AttributeEntry, DataPoint, DataType, MetadataEntry, SensorEntry, Value, -}; - -pub enum Error { - ParseError, -} - -impl From for DataPoint { - fn from(dp: broker::Datapoint) -> Self { - DataPoint { - value: dp.value.into(), - ts: dp.ts.into(), - } - } -} - -impl TryFrom for String { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => Ok(value), - } - } -} - -impl TryFrom for bool { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for i32 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for i64 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for u32 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for u64 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for f32 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for f64 { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => value.parse::().map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => Ok(array), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Scalar(_) | Value::None => Err(Error::ParseError), - Value::Array(array) => array - .iter() - .map(|value| value.parse::()) - .collect::, _>>() - .map_err(|_| Error::ParseError), - } - } -} - -impl From for Value { - fn from(value: broker::DataValue) -> Self { - match value { - broker::DataValue::NotAvailable => Value::None, - broker::DataValue::Bool(value) => Value::Scalar(value.to_string()), - broker::DataValue::String(value) => Value::Scalar(value), - broker::DataValue::Int32(value) => Value::Scalar(value.to_string()), - broker::DataValue::Int64(value) => Value::Scalar(value.to_string()), - broker::DataValue::Uint32(value) => Value::Scalar(value.to_string()), - broker::DataValue::Uint64(value) => Value::Scalar(value.to_string()), - broker::DataValue::Float(value) => Value::Scalar(value.to_string()), - broker::DataValue::Double(value) => Value::Scalar(value.to_string()), - broker::DataValue::BoolArray(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::StringArray(array) => Value::Array(array), - broker::DataValue::Int32Array(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::Int64Array(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::Uint32Array(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::Uint64Array(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::FloatArray(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - broker::DataValue::DoubleArray(array) => { - Value::Array(array.iter().map(|value| value.to_string()).collect()) - } - } - } -} - -impl TryFrom for SystemTime { - type Error = Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Array(_) | Value::None => Err(Error::ParseError), - Value::Scalar(value) => chrono::DateTime::parse_from_rfc3339(&value) - .map(|datetime| datetime.with_timezone(&chrono::Utc)) - .map(SystemTime::from) - .map_err(|_| Error::ParseError), - } - } -} - -impl From for DataType { - fn from(value: broker::DataType) -> Self { - match value { - broker::DataType::String => DataType::String, - broker::DataType::Bool => DataType::Boolean, - broker::DataType::Int8 => DataType::Int8, - broker::DataType::Int16 => DataType::Int16, - broker::DataType::Int32 => DataType::Int32, - broker::DataType::Int64 => DataType::Int64, - broker::DataType::Uint8 => DataType::Uint8, - broker::DataType::Uint16 => DataType::Uint16, - broker::DataType::Uint32 => DataType::Uint32, - broker::DataType::Uint64 => DataType::Uint64, - broker::DataType::Float => DataType::Float, - broker::DataType::Double => DataType::Double, - broker::DataType::StringArray => DataType::StringArray, - broker::DataType::BoolArray => DataType::BoolArray, - broker::DataType::Int8Array => DataType::Int8Array, - broker::DataType::Int16Array => DataType::Int16Array, - broker::DataType::Int32Array => DataType::Int32Array, - broker::DataType::Int64Array => DataType::Int64Array, - broker::DataType::Uint8Array => DataType::Uint8Array, - broker::DataType::Uint16Array => DataType::Uint16Array, - broker::DataType::Uint32Array => DataType::Uint32Array, - broker::DataType::Uint64Array => DataType::Uint64Array, - broker::DataType::FloatArray => DataType::FloatArray, - broker::DataType::DoubleArray => DataType::DoubleArray, - } - } -} -impl From<&broker::Metadata> for MetadataEntry { - fn from(metadata: &broker::Metadata) -> Self { - match metadata.entry_type { - broker::EntryType::Sensor => MetadataEntry::Sensor(SensorEntry { - datatype: metadata.data_type.clone().into(), - description: metadata.description.clone(), - comment: None, - unit: None, - allowed: metadata.allowed.clone().map(|allowed| allowed.into()), - min: None, - max: None, - }), - broker::EntryType::Attribute => MetadataEntry::Attribute(AttributeEntry { - datatype: metadata.data_type.clone().into(), - description: metadata.description.clone(), - unit: None, - allowed: metadata.allowed.clone().map(|allowed| allowed.into()), - default: None, // TODO: Add to metadata - }), - broker::EntryType::Actuator => MetadataEntry::Actuator(ActuatorEntry { - description: metadata.description.clone(), - comment: None, - datatype: metadata.data_type.clone().into(), - unit: None, - allowed: metadata.allowed.clone().map(|allowed| allowed.into()), - min: None, - max: None, - }), - } - } -} - -impl Value { - pub fn try_into_type(self, data_type: &broker::DataType) -> Result { - match data_type { - broker::DataType::String => String::try_from(self).map(broker::DataValue::String), - broker::DataType::Bool => bool::try_from(self).map(broker::DataValue::Bool), - broker::DataType::Int8 | broker::DataType::Int16 | broker::DataType::Int32 => { - i32::try_from(self).map(broker::DataValue::Int32) - } - broker::DataType::Int64 => i64::try_from(self).map(broker::DataValue::Int64), - broker::DataType::Uint8 | broker::DataType::Uint16 | broker::DataType::Uint32 => { - u32::try_from(self).map(broker::DataValue::Uint32) - } - broker::DataType::Uint64 => u64::try_from(self).map(broker::DataValue::Uint64), - broker::DataType::Float => f32::try_from(self).map(broker::DataValue::Float), - broker::DataType::Double => f64::try_from(self).map(broker::DataValue::Double), - // broker::DataType::Timestamp => { - // SystemTime::try_from(self).map(broker::DataValue::Timestamp) - // } - broker::DataType::StringArray => { - Vec::::try_from(self).map(broker::DataValue::StringArray) - } - broker::DataType::BoolArray => { - Vec::::try_from(self).map(broker::DataValue::BoolArray) - } - broker::DataType::Int8Array - | broker::DataType::Int16Array - | broker::DataType::Int32Array => { - Vec::::try_from(self).map(broker::DataValue::Int32Array) - } - broker::DataType::Int64Array => { - Vec::::try_from(self).map(broker::DataValue::Int64Array) - } - broker::DataType::Uint8Array - | broker::DataType::Uint16Array - | broker::DataType::Uint32Array => { - Vec::::try_from(self).map(broker::DataValue::Uint32Array) - } - broker::DataType::Uint64Array => { - Vec::::try_from(self).map(broker::DataValue::Uint64Array) - } - broker::DataType::FloatArray => { - Vec::::try_from(self).map(broker::DataValue::FloatArray) - } - broker::DataType::DoubleArray => { - Vec::::try_from(self).map(broker::DataValue::DoubleArray) - } - } - } -} - -impl std::fmt::Display for DataType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.pad(match self { - DataType::String => "string", - DataType::Boolean => "bool", - DataType::Int8 => "int8", - DataType::Int16 => "int16", - DataType::Int32 => "int32", - DataType::Int64 => "int64", - DataType::Uint8 => "uint8", - DataType::Uint16 => "uint16", - DataType::Uint32 => "uint32", - DataType::Uint64 => "uint64", - DataType::Float => "float", - DataType::Double => "double", - DataType::StringArray => "string[]", - DataType::BoolArray => "bool[]", - DataType::Int8Array => "int8[]", - DataType::Int16Array => "int16[]", - DataType::Int32Array => "int32[]", - DataType::Int64Array => "int64[]", - DataType::Uint8Array => "uint8[]", - DataType::Uint16Array => "uint16[]", - DataType::Uint32Array => "uint32[]", - DataType::Uint64Array => "uint64[]", - DataType::FloatArray => "float[]", - DataType::DoubleArray => "double[]", - }) - } -} diff --git a/kuksa_databroker/databroker/src/viss/v2/mod.rs b/kuksa_databroker/databroker/src/viss/v2/mod.rs deleted file mode 100644 index 74df5c54d..000000000 --- a/kuksa_databroker/databroker/src/viss/v2/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -mod conversions; - -pub(crate) mod server; -pub(crate) mod types; - -pub use types::*; diff --git a/kuksa_databroker/databroker/src/viss/v2/server.rs b/kuksa_databroker/databroker/src/viss/v2/server.rs deleted file mode 100644 index 91a69f62d..000000000 --- a/kuksa_databroker/databroker/src/viss/v2/server.rs +++ /dev/null @@ -1,438 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::{ - collections::{HashMap, HashSet}, - convert::TryFrom, - pin::Pin, - sync::Arc, - time::SystemTime, -}; - -use futures::{ - stream::{AbortHandle, Abortable}, - Stream, StreamExt, -}; -use tokio::sync::RwLock; -use tracing::warn; - -use crate::{ - authorization::Authorization, - broker::{self, AuthorizedAccess, UpdateError}, - permissions::{self, Permissions}, -}; - -use super::{conversions, types::*}; - -#[tonic::async_trait] -pub(crate) trait Viss: Send + Sync + 'static { - async fn get(&self, request: GetRequest) -> Result; - async fn set(&self, request: SetRequest) -> Result; - - type SubscribeStream: Stream> - + Send - + 'static; - - async fn subscribe( - &self, - request: SubscribeRequest, - ) -> Result<(SubscribeSuccessResponse, Self::SubscribeStream), SubscribeErrorResponse>; - - async fn unsubscribe( - &self, - request: UnsubscribeRequest, - ) -> Result; -} - -pub struct SubscriptionHandle { - abort_handle: AbortHandle, -} - -impl From for SubscriptionHandle { - fn from(abort_handle: AbortHandle) -> Self { - Self { abort_handle } - } -} - -impl Drop for SubscriptionHandle { - fn drop(&mut self) { - self.abort_handle.abort(); - } -} - -pub struct Server { - broker: broker::DataBroker, - authorization: Authorization, - subscriptions: Arc>>, -} - -impl Server { - pub fn new(broker: broker::DataBroker, authorization: Authorization) -> Self { - Self { - broker, - authorization, - subscriptions: Arc::new(RwLock::new(HashMap::new())), - } - } -} - -#[tonic::async_trait] -impl Viss for Server { - async fn get(&self, request: GetRequest) -> Result { - let request_id = request.request_id; - - if let Some(Filter::StaticMetadata(_)) = &request.filter { - // Authorization not required for metadata, don't bail if an - // access token is missing. - let broker = self.broker.authorized_access(&permissions::ALLOW_NONE); - let metadata = generate_metadata(&broker, request.path.as_ref()).await; - return Ok(GetSuccessResponse::Metadata(MetadataResponse { - request_id, - metadata, - })); - } - let permissions = resolve_permissions(&self.authorization, &request.authorization) - .map_err(|error| GetErrorResponse { - request_id: request_id.clone(), - error, - ts: SystemTime::now().into(), - })?; - let broker = self.broker.authorized_access(&permissions); - - // Get datapoints - match broker.get_datapoint_by_path(request.path.as_ref()).await { - Ok(datapoint) => { - let dp = DataPoint::from(datapoint); - Ok(GetSuccessResponse::Data(DataResponse { - request_id, - data: Data::Object(DataObject { - path: request.path, - dp, - }), - })) - } - Err(err) => Err(GetErrorResponse { - request_id, - ts: SystemTime::now().into(), - error: match err { - broker::ReadError::NotFound => Error::NotFoundInvalidPath, - broker::ReadError::PermissionDenied => Error::Forbidden, - broker::ReadError::PermissionExpired => Error::UnauthorizedTokenExpired, - }, - }), - } - } - - async fn set(&self, request: SetRequest) -> Result { - let request_id = request.request_id; - let permissions = resolve_permissions(&self.authorization, &request.authorization) - .map_err(|error| SetErrorResponse { - request_id: request_id.clone(), - error, - ts: SystemTime::now().into(), - })?; - let broker = self.broker.authorized_access(&permissions); - - match broker.get_metadata_by_path(request.path.as_ref()).await { - Some(metadata) => { - if metadata.entry_type != broker::EntryType::Actuator { - return Err(SetErrorResponse { - request_id, - error: Error::UnauthorizedReadOnly, - ts: SystemTime::now().into(), - }); - } - - let value = request.value; - - let update = value - .try_into_type(&metadata.data_type) - .map(|actuator_target| broker::EntryUpdate { - path: None, - datapoint: None, - actuator_target: Some(Some(broker::Datapoint { - value: actuator_target, - source_ts: None, - ts: SystemTime::now(), - })), - entry_type: None, - data_type: None, - description: None, - allowed: None, - unit: None, - }) - .map_err(|err| SetErrorResponse { - request_id: request_id.clone(), - error: match err { - conversions::Error::ParseError => Error::BadRequest { - msg: Some(format!( - "Failed to parse the value as a {}", - DataType::from(metadata.data_type.clone()) - )), - }, - }, - ts: SystemTime::now().into(), - })?; - - let updates = vec![(metadata.id, update)]; - match broker.update_entries(updates).await { - Ok(()) => Ok(SetSuccessResponse { - request_id, - ts: SystemTime::now().into(), - }), - Err(errors) => { - let error = if let Some((_, error)) = errors.first() { - match error { - UpdateError::NotFound => Error::NotFoundInvalidPath, - UpdateError::WrongType => Error::BadRequest { - msg: Some("Wrong data type.".into()), - }, - UpdateError::OutOfBounds => Error::BadRequest { - msg: Some("Value out of bounds.".into()), - }, - UpdateError::UnsupportedType => Error::BadRequest { - msg: Some("Unsupported data type.".into()), - }, - UpdateError::PermissionDenied => Error::Forbidden, - UpdateError::PermissionExpired => Error::UnauthorizedTokenExpired, - } - } else { - Error::InternalServerError - }; - - Err(SetErrorResponse { - request_id, - error, - ts: SystemTime::now().into(), - }) - } - } - } - None => { - // Not found - Err(SetErrorResponse { - request_id, - error: Error::NotFoundInvalidPath, - ts: SystemTime::now().into(), - }) - } - } - } - - type SubscribeStream = Pin< - Box< - dyn Stream> - + Send - + Sync - + 'static, - >, - >; - - async fn subscribe( - &self, - request: SubscribeRequest, - ) -> Result<(SubscribeSuccessResponse, Self::SubscribeStream), SubscribeErrorResponse> { - let request_id = request.request_id; - let permissions = resolve_permissions(&self.authorization, &request.authorization) - .map_err(|error| SubscribeErrorResponse { - request_id: request_id.clone(), - error, - ts: SystemTime::now().into(), - })?; - let broker = self.broker.authorized_access(&permissions); - - let Some(entries) = broker - .get_id_by_path(request.path.as_ref()) - .await - .map(|id| HashMap::from([(id, HashSet::from([broker::Field::Datapoint]))])) - else { - return Err(SubscribeErrorResponse { - request_id, - error: Error::NotFoundInvalidPath, - ts: SystemTime::now().into(), - }); - }; - - match broker.subscribe(entries).await { - Ok(stream) => { - let subscription_id = SubscriptionId::new(); - - let (abort_handle, abort_registration) = AbortHandle::new_pair(); - - // Make the stream abortable - let stream = Abortable::new(stream, abort_registration); - - // Register abort handle - self.subscriptions.write().await.insert( - subscription_id.clone(), - SubscriptionHandle::from(abort_handle), - ); - - let stream = convert_to_viss_stream(subscription_id.clone(), stream); - - Ok(( - SubscribeSuccessResponse { - request_id, - subscription_id, - ts: SystemTime::now().into(), - }, - Box::pin(stream), - )) - } - Err(err) => Err(SubscribeErrorResponse { - request_id, - error: match err { - broker::SubscriptionError::NotFound => Error::NotFoundInvalidPath, - broker::SubscriptionError::InvalidInput => Error::NotFoundInvalidPath, - broker::SubscriptionError::InternalError => Error::InternalServerError, - }, - ts: SystemTime::now().into(), - }), - } - } - - async fn unsubscribe( - &self, - request: UnsubscribeRequest, - ) -> Result { - let subscription_id = request.subscription_id; - let request_id = request.request_id; - match self.subscriptions.write().await.remove(&subscription_id) { - Some(_) => { - // Stream is aborted when handle is dropped - Ok(UnsubscribeSuccessResponse { - request_id, - subscription_id, - ts: SystemTime::now().into(), - }) - } - None => Err(UnsubscribeErrorResponse { - request_id, - subscription_id, - error: Error::NotFoundInvalidSubscriptionId, - ts: SystemTime::now().into(), - }), - } - } -} - -fn convert_to_viss_stream( - subscription_id: SubscriptionId, - stream: impl Stream, -) -> impl Stream> { - stream.map(move |mut item| { - let ts = SystemTime::now().into(); - let subscription_id = subscription_id.clone(); - match item.updates.pop() { - Some(item) => match (item.update.path, item.update.datapoint) { - (Some(path), Some(datapoint)) => Ok(SubscriptionEvent { - subscription_id, - data: Data::Object(DataObject { - path: path.into(), - dp: datapoint.into(), - }), - ts, - }), - (_, _) => Err(SubscriptionErrorEvent { - subscription_id, - error: Error::InternalServerError, - ts, - }), - }, - None => Err(SubscriptionErrorEvent { - subscription_id, - error: Error::InternalServerError, - ts, - }), - } - }) -} - -fn resolve_permissions( - authorization: &Authorization, - token: &Option, -) -> Result { - match authorization { - Authorization::Disabled => Ok(permissions::ALLOW_ALL.clone()), - Authorization::Enabled { token_decoder } => match token { - Some(token) => match token_decoder.decode(token) { - Ok(claims) => match Permissions::try_from(claims) { - Ok(permissions) => Ok(permissions), - Err(_) => Err(Error::UnauthorizedTokenInvalid), - }, - Err(_) => Err(Error::UnauthorizedTokenInvalid), - }, - None => Err(Error::UnauthorizedTokenMissing), - }, - } -} - -async fn generate_metadata<'a>( - db: &'a AuthorizedAccess<'_, '_>, - path: &str, -) -> HashMap { - let mut metadata: HashMap = HashMap::new(); - - // We want to remove all but the last "component" present in the path. - // For example, if requesting "Vehicle.Driver", we want to match - // everything starting with "Vehicle.Driver" but include "Driver" - // as the top level entry returned as metadata. - let prefix_to_strip = match path.rsplit_once('.') { - Some((prefix_excl_dot, _leaf)) => &path[..=prefix_excl_dot.len()], - None => "", - }; - - // Include everything that starts with the requested path. - // Insert into the metadata tree, with the top level being the last - // "component" of the branch as described above. - db.for_each_entry(|entry| { - let entry_metadata = entry.metadata(); - let entry_path = &entry_metadata.path; - if entry_path.starts_with(path) { - if let Some(path) = entry_path.strip_prefix(prefix_to_strip) { - insert_entry(&mut metadata, path, entry_metadata.into()); - } - } - }) - .await; - - metadata -} - -fn insert_entry(entries: &mut HashMap, path: &str, entry: MetadataEntry) { - // Get the leftmost path component by splitting at '.'. - // `split_once` will return None if there is only one component, - // which means it's the leaf. - match path.split_once('.') { - Some((key, path)) => match entries.get_mut(key) { - Some(MetadataEntry::Branch(branch_entry)) => { - insert_entry(&mut branch_entry.children, path, entry); - } - Some(_) => { - warn!("Should only be possible for branches to exist here"); - // ignore - } - None => { - let mut branch = BranchEntry { - description: "".into(), - children: HashMap::default(), - }; - insert_entry(&mut branch.children, path, entry); - entries.insert(key.to_owned(), MetadataEntry::Branch(branch)); - } - }, - None => { - entries.insert(path.to_owned(), entry); - } - } -} diff --git a/kuksa_databroker/databroker/src/viss/v2/types.rs b/kuksa_databroker/databroker/src/viss/v2/types.rs deleted file mode 100644 index c0fe23d71..000000000 --- a/kuksa_databroker/databroker/src/viss/v2/types.rs +++ /dev/null @@ -1,553 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::{collections::HashMap, time::SystemTime}; - -use serde::{Deserialize, Serialize}; - -#[derive(Deserialize)] -#[serde(tag = "action")] -pub enum Request { - #[serde(rename = "get")] - Get(GetRequest), - #[serde(rename = "set")] - Set(SetRequest), - #[serde(rename = "subscribe")] - Subscribe(SubscribeRequest), - #[serde(rename = "unsubscribe")] - Unsubscribe(UnsubscribeRequest), -} - -// Identify responses using the `Response` trait to prevent -// responding with other serializable things. -pub trait Response: Serialize {} - -impl Response for GetSuccessResponse {} -impl Response for GetErrorResponse {} - -impl Response for SetSuccessResponse {} -impl Response for SetErrorResponse {} - -impl Response for SubscribeSuccessResponse {} -impl Response for SubscribeErrorResponse {} - -impl Response for UnsubscribeSuccessResponse {} -impl Response for UnsubscribeErrorResponse {} - -impl Response for SubscriptionEvent {} -impl Response for SubscriptionErrorEvent {} - -impl Response for GenericErrorResponse {} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GetRequest { - pub path: Path, - pub request_id: RequestId, - pub authorization: Option, - pub filter: Option, -} - -#[derive(Serialize)] -#[serde(untagged)] -pub enum GetSuccessResponse { - Data(DataResponse), - Metadata(MetadataResponse), -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "get", rename_all = "camelCase")] -pub struct DataResponse { - pub request_id: RequestId, - pub data: Data, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "get", rename_all = "camelCase")] -pub struct MetadataResponse { - pub request_id: RequestId, - pub metadata: HashMap, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "get", rename_all = "camelCase")] -pub struct GetErrorResponse { - pub request_id: RequestId, - pub error: Error, - pub ts: Timestamp, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SetRequest { - pub path: Path, - pub value: Value, - pub request_id: RequestId, - pub authorization: Option, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "set", rename_all = "camelCase")] -pub struct SetSuccessResponse { - pub request_id: RequestId, - pub ts: Timestamp, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "set", rename_all = "camelCase")] -pub struct SetErrorResponse { - pub request_id: RequestId, - pub error: Error, - pub ts: Timestamp, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SubscribeRequest { - pub path: Path, - pub request_id: RequestId, - pub authorization: Option, - // filter: Option, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "subscribe", rename_all = "camelCase")] -pub struct SubscribeSuccessResponse { - pub request_id: RequestId, - pub subscription_id: SubscriptionId, - pub ts: Timestamp, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "subscribe", rename_all = "camelCase")] -pub struct SubscribeErrorResponse { - pub request_id: RequestId, - pub error: Error, - pub ts: Timestamp, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "subscription", rename_all = "camelCase")] -pub struct SubscriptionEvent { - pub subscription_id: SubscriptionId, - pub data: Data, - pub ts: Timestamp, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "subscription", rename_all = "camelCase")] -pub struct SubscriptionErrorEvent { - pub subscription_id: SubscriptionId, - pub error: Error, - pub ts: Timestamp, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct UnsubscribeRequest { - pub request_id: RequestId, - pub subscription_id: SubscriptionId, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "unsubscribe", rename_all = "camelCase")] -pub struct UnsubscribeSuccessResponse { - pub request_id: RequestId, - pub subscription_id: SubscriptionId, - pub ts: Timestamp, -} - -#[derive(Serialize)] -#[serde(tag = "action", rename = "unsubscribe", rename_all = "camelCase")] -pub struct UnsubscribeErrorResponse { - pub request_id: RequestId, - pub subscription_id: SubscriptionId, - pub error: Error, - pub ts: Timestamp, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GenericRequest { - pub action: Option, - pub request_id: Option, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GenericErrorResponse { - pub action: Option, - pub request_id: Option, - pub error: Error, -} - -#[derive(Deserialize)] -#[serde(tag = "type")] -pub enum Filter { - #[serde(rename = "static-metadata")] - StaticMetadata(StaticMetadataFilter), -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticMetadataFilter { - // pub parameters: Option, -} - -// Unique id value specified by the client. Returned by the server in the -// response and used by the client to link the request and response messages. -// The value MAY be an integer or a Universally Unique Identifier (UUID). -#[derive(Serialize, Deserialize, Clone)] -#[serde(transparent)] -pub struct RequestId(String); - -// The path consists a sequence of VSS node names separated by a delimiter. -// VSS specifies the dot (.) as delimiter, which therefore is the recommended -// choice also in this specification. However, in HTTP URLs the conventional -// delimiter is slash (/), therefore also this delimiter is supported. -// To exemplify, the path expression from traversing the nodes -// Vehicle, Car, Engine, RPM can be "Vehicle.Car.Engine.RPM", or -// "Vehicle/Car/Engine/RPM". A mix of delimiters in the same path expression -// SHOULD be avoided. -// The path MUST not contain any wildcard characters ("*"), for such needs -// see 7.1 Paths Filter Operation. -#[derive(Serialize, Deserialize, Clone)] -#[serde(transparent)] -pub struct Path(String); - -// A handle identifying a subscription session. -#[derive(Serialize, Deserialize, Clone, Eq, Hash, PartialEq)] -#[serde(transparent)] -pub struct SubscriptionId(String); - -// Timestamps in transport payloads MUST conform to the [ISO8601] standard, -// using the UTC format with a trailing Z. Time resolution SHALL at least be -// seconds, with sub-second resolution as an optional degree of precision when -// desired. The time and date format shall be as shown below, where the -// sub-second data and delimiter is optional. -// -// YYYY-MM-DDTHH:MM:SS.ssssssZ -// -pub struct Timestamp { - ts: SystemTime, -} - -#[derive(Serialize)] -#[serde(untagged)] -pub enum Data { - Object(DataObject), - #[allow(dead_code)] - Array(Vec), -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DataObject { - pub path: Path, - pub dp: DataPoint, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DataPoint { - pub value: Value, - pub ts: Timestamp, -} - -#[derive(Serialize, Deserialize, Clone)] -#[serde(untagged)] -pub enum Value { - None, - Scalar(String), - Array(Vec), -} - -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "camelCase")] -pub enum MetadataEntry { - Branch(BranchEntry), - Sensor(SensorEntry), - Attribute(AttributeEntry), - Actuator(ActuatorEntry), -} - -#[derive(Serialize)] -pub struct BranchEntry { - pub description: String, - pub children: HashMap, -} - -#[derive(Serialize)] -pub struct SensorEntry { - pub datatype: DataType, - pub description: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub comment: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub unit: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub allowed: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub min: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max: Option, -} - -#[derive(Serialize)] -pub struct AttributeEntry { - pub datatype: DataType, - pub description: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub unit: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub allowed: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub default: Option, -} - -#[derive(Serialize)] -pub struct ActuatorEntry { - pub datatype: DataType, - pub description: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub comment: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub unit: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub allowed: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub min: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max: Option, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub enum DataType { - String, - Boolean, - Int8, - Int16, - Int32, - Int64, - Uint8, - Uint16, - Uint32, - Uint64, - Float, - Double, - #[serde(rename = "string[]")] - StringArray, - #[serde(rename = "boolean[]")] - BoolArray, - #[serde(rename = "int8[]")] - Int8Array, - #[serde(rename = "int16[]")] - Int16Array, - #[serde(rename = "int32[]")] - Int32Array, - #[serde(rename = "int64[]")] - Int64Array, - #[serde(rename = "uint8[]")] - Uint8Array, - #[serde(rename = "uint16[]")] - Uint16Array, - #[serde(rename = "uint32[]")] - Uint32Array, - #[serde(rename = "uint64[]")] - Uint64Array, - #[serde(rename = "float[]")] - FloatArray, - #[serde(rename = "double[]")] - DoubleArray, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ErrorSpec { - pub number: i32, - pub reason: String, - pub message: String, -} - -#[derive(Serialize, Clone)] -#[serde(into = "ErrorSpec")] -#[allow(dead_code, clippy::enum_variant_names)] -pub enum Error { - BadRequest { msg: Option }, - UnauthorizedTokenExpired, - UnauthorizedTokenInvalid, - UnauthorizedTokenMissing, - UnauthorizedReadOnly, - Forbidden, - NotFoundInvalidPath, - NotFoundUnavailableData, - NotFoundInvalidSubscriptionId, - InternalServerError, - NotImplemented, -} - -impl From for ErrorSpec { - fn from(error: Error) -> Self { - match error { - // Error Number Reason Message - // NotModified 304 not_modified No changes have been made by the server. - // BadRequest 400 bad_request The server is unable to fulfil the client request because the request is malformed. - Error::BadRequest{ msg: custom_msg } => ErrorSpec { - number: 400, - reason: "bad_request".into(), - message: custom_msg.unwrap_or("The server is unable to fulfil the client request because the request is malformed.".into()), - }, - // BadRequest 400 filter_invalid Filter requested on non-primitive type. - // BadRequest 400 invalid_duration Time duration is invalid. - // BadRequest 400 invalid_value The requested set value is invalid. - // Unauthorized 401 token_expired Access token has expired. - Error::UnauthorizedTokenExpired => ErrorSpec { - number: 401, - reason: "token_expired".into(), - message: "Access token has expired.".into(), - }, - // Unauthorized 401 token_invalid Access token is invalid. - Error::UnauthorizedTokenInvalid => ErrorSpec { - number: 401, - reason: "token_invalid".into(), - message: "Access token is invalid.".into(), - }, - // Unauthorized 401 token_missing Access token is missing. - Error::UnauthorizedTokenMissing => ErrorSpec { - number: 401, - reason: "token_missing".into(), - message: "Access token is missing.".into(), - }, - // Unauthorized 401 too_many_attempts The client has failed to authenticate too many times. - // Unauthorized 401 read_only The desired signal cannot be set since it is a read only signal. - Error::UnauthorizedReadOnly => ErrorSpec { - number: 401, - reason: "read_only".into(), - message: "The desired signal cannot be set since it is a read only signal.".into(), - }, - // Forbidden 403 user_forbidden The user is not permitted to access the requested resource. Retrying does not help. - Error::Forbidden => ErrorSpec { - number: 403, - reason: "user_forbidden".into(), - message: "The user is not permitted to access the requested resource. Retrying does not help.".into(), - }, - // Forbidden 403 user_unknown The user is unknown. Retrying does not help. - // Forbidden 403 device_forbidden The device is not permitted to access the requested resource. Retrying does not help. - // Forbidden 403 device_unknown The device is unknown. Retrying does not help. - // NotFound 404 invalid_path The specified data path does not exist. - Error::NotFoundInvalidPath => ErrorSpec { - number: 404, - reason: "invalid_path".into(), - message: "The specified data path does not exist.".into(), - }, - // NotFound 404 private_path The specified data path is private and the request is not authorized to access signals on this path. - // NotFound 404 unavailable_data The requested data was not found. - Error::NotFoundUnavailableData => ErrorSpec { - number: 404, - reason: "unavailable_data".into(), - message: "The requested data was not found.".into(), - }, - // NotFound 404 invalid_subscription_id The specified subscription was not found. - Error::NotFoundInvalidSubscriptionId => ErrorSpec { - number: 404, - reason: "invalid_subscription_id".into(), - message: "The specified subscription was not found.".into(), - }, - // NotAcceptable 406 insufficient_privileges The privileges represented by the access token are not sufficient. - // NotAcceptable 406 not_acceptable The server is unable to generate content that is acceptable to the client - // TooManyRequests 429 too_many_requests The client has sent the server too many requests in a given amount of time. - // InternalServerError 500 internal_server_error The server encountered an unexpected condition which prevented it from fulfilling the request. - Error::InternalServerError => ErrorSpec { - number: 500, - reason: "internal_server_error".into(), - message: "The server encountered an unexpected condition which prevented it from fulfilling the request.".into(), - }, - // NotImplemented 501 not_implemented The server does not support the functionality required to fulfill the request. - Error::NotImplemented => ErrorSpec { - number: 501, - reason: "not_implemented".into(), - message: "The server does not support the functionality required to fulfill the request.".into(), - }, - // BadGateway 502 bad_gateway The server was acting as a gateway or proxy and received an invalid response from an upstream server. - // ServiceUnavailable 503 service_unavailable The server is currently unable to handle the request due to a temporary overload or scheduled maintenance (which may be alleviated after some delay). - // GatewayTimeout 504 gateway_timeout The server did not receive a timely response from an upstream server it needed to access in order to complete the request. - } - } -} - -impl AsRef for Path { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl From for String { - fn from(value: Path) -> Self { - value.0 - } -} - -impl From for Path { - fn from(value: String) -> Self { - Path(value) - } -} - -impl From for SubscriptionId { - fn from(value: String) -> Self { - SubscriptionId(value) - } -} - -impl From for String { - fn from(value: SubscriptionId) -> Self { - value.0 - } -} - -impl AsRef for RequestId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl From for Timestamp { - fn from(ts: SystemTime) -> Self { - Timestamp { ts } - } -} - -impl Serialize for Timestamp { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let utc_time: chrono::DateTime = self.ts.into(); - let use_z = true; - let serialized = utc_time.to_rfc3339_opts(chrono::SecondsFormat::Millis, use_z); - serializer.serialize_str(&serialized) - } -} - -impl SubscriptionId { - pub fn new() -> Self { - Self(uuid::Uuid::new_v4().to_string()) - } -} - -impl Default for SubscriptionId { - fn default() -> Self { - Self::new() - } -} diff --git a/kuksa_databroker/databroker/src/vss.rs b/kuksa_databroker/databroker/src/vss.rs deleted file mode 100644 index a79b0d54a..000000000 --- a/kuksa_databroker/databroker/src/vss.rs +++ /dev/null @@ -1,657 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::collections::{BTreeMap, HashMap}; -use std::fmt; - -use serde::Deserialize; - -use crate::types; - -#[derive(Debug, Deserialize)] -struct RootEntry(HashMap); - -// While it's possible to use serde's "tagged enum" for parsing VSS json, -// doing that breaks serde's ability to track line numbers when reporting -// parsing errors. (https://github.com/dtolnay/serde-yaml/issues/153) -// -// #[derive(Debug, Deserialize)] -// #[serde(tag = "type", rename_all = "camelCase")] -// pub enum Entry { -// Branch(BranchEntry), -// Actuator(ActuatorEntry), -// Attribute(AttributeEntry), -// Sensor(SensorEntry), -// } -// -// Instead, a single Entry consisting of the superset of possible fields is used. -// -#[derive(Debug, Deserialize)] -pub struct Entry { - // all - #[serde(rename = "type")] - entry_type: EntryType, - description: String, - comment: Option, - - // branch only - children: Option>, - - // all data entry types - #[serde(rename = "datatype")] - data_type: Option, - unit: Option, - min: Option, - max: Option, - allowed: Option>, - #[serde(rename = "x-kuksa-changetype")] - change_type: Option, - - // attribute entry type only - default: Option, -} - -pub struct DataEntry { - pub data_type: types::DataType, - pub entry_type: types::EntryType, - pub change_type: types::ChangeType, - pub description: String, - pub comment: Option, - pub unit: Option, - pub min: Option, - pub max: Option, - pub allowed: Option, - pub default: Option, -} - -#[derive(Debug, Deserialize)] -pub enum EntryType { - #[serde(rename = "actuator")] - Actuator, - - #[serde(rename = "attribute")] - Attribute, - - #[serde(rename = "branch")] - Branch, - - #[serde(rename = "sensor")] - Sensor, -} - -#[derive(Debug, Deserialize)] -pub enum ChangeType { - #[serde(rename = "static")] - Static, - #[serde(rename = "onchange")] - OnChange, - #[serde(rename = "continuous")] - Continuous, -} - -#[derive(Debug, Deserialize)] -pub enum DataType { - #[serde(rename = "string")] - String, - #[serde(rename = "boolean")] - Boolean, - #[serde(rename = "int8")] - Int8, - #[serde(rename = "int16")] - Int16, - #[serde(rename = "int32")] - Int32, - #[serde(rename = "int64")] - Int64, - #[serde(rename = "uint8")] - Uint8, - #[serde(rename = "uint16")] - Uint16, - #[serde(rename = "uint32")] - Uint32, - #[serde(rename = "uint64")] - Uint64, - #[serde(rename = "float")] - Float, - #[serde(rename = "double")] - Double, - #[serde(rename = "string[]")] - StringArray, - #[serde(rename = "boolean[]")] - BooleanArray, - #[serde(rename = "int8[]")] - Int8Array, - #[serde(rename = "int16[]")] - Int16Array, - #[serde(rename = "int32[]")] - Int32Array, - #[serde(rename = "int64[]")] - Int64Array, - #[serde(rename = "uint8[]")] - Uint8Array, - #[serde(rename = "uint16[]")] - Uint16Array, - #[serde(rename = "uint32[]")] - Uint32Array, - #[serde(rename = "uint64[]")] - Uint64Array, - #[serde(rename = "float[]")] - FloatArray, - #[serde(rename = "double[]")] - DoubleArray, -} - -#[derive(Debug)] -pub enum Error { - ParseError(String), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::ParseError(error) => write!(f, "{error}"), - } - } -} - -impl From for Error { - fn from(from: serde_json::Error) -> Self { - Error::ParseError(from.to_string()) - } -} - -impl std::error::Error for Error {} - -impl From for types::DataType { - fn from(from: DataType) -> Self { - match from { - DataType::String => types::DataType::String, - DataType::Boolean => types::DataType::Bool, - DataType::Int8 => types::DataType::Int8, - DataType::Int16 => types::DataType::Int16, - DataType::Int32 => types::DataType::Int32, - DataType::Int64 => types::DataType::Int64, - DataType::Uint8 => types::DataType::Uint8, - DataType::Uint16 => types::DataType::Uint16, - DataType::Uint32 => types::DataType::Uint32, - DataType::Uint64 => types::DataType::Uint64, - DataType::Float => types::DataType::Float, - DataType::Double => types::DataType::Double, - DataType::StringArray => types::DataType::StringArray, - DataType::BooleanArray => types::DataType::BoolArray, - DataType::Int8Array => types::DataType::Int8Array, - DataType::Int16Array => types::DataType::Int16Array, - DataType::Int32Array => types::DataType::Int32Array, - DataType::Int64Array => types::DataType::Int64Array, - DataType::Uint8Array => types::DataType::Uint8Array, - DataType::Uint16Array => types::DataType::Uint16Array, - DataType::Uint32Array => types::DataType::Uint32Array, - DataType::Uint64Array => types::DataType::Uint64Array, - DataType::FloatArray => types::DataType::FloatArray, - DataType::DoubleArray => types::DataType::DoubleArray, - } - } -} - -fn try_from_json_array( - array: Option>, - data_type: &types::DataType, -) -> Result, Error> { - match array { - Some(array) => { - let value = Some(serde_json::Value::Array(array)); - match data_type { - types::DataType::String => { - try_from_json_value(value, &types::DataType::StringArray) - } - types::DataType::Bool => try_from_json_value(value, &types::DataType::BoolArray), - types::DataType::Int8 => try_from_json_value(value, &types::DataType::Int8Array), - types::DataType::Int16 => try_from_json_value(value, &types::DataType::Int16Array), - types::DataType::Int32 => try_from_json_value(value, &types::DataType::Int32Array), - types::DataType::Int64 => try_from_json_value(value, &types::DataType::Int64Array), - types::DataType::Uint8 => try_from_json_value(value, &types::DataType::Uint8Array), - types::DataType::Uint16 => { - try_from_json_value(value, &types::DataType::Uint16Array) - } - types::DataType::Uint32 => { - try_from_json_value(value, &types::DataType::Uint32Array) - } - types::DataType::Uint64 => { - try_from_json_value(value, &types::DataType::Uint64Array) - } - types::DataType::Float => try_from_json_value(value, &types::DataType::FloatArray), - types::DataType::Double => { - try_from_json_value(value, &types::DataType::DoubleArray) - } - types::DataType::StringArray - | types::DataType::BoolArray - | types::DataType::Int8Array - | types::DataType::Int16Array - | types::DataType::Int32Array - | types::DataType::Int64Array - | types::DataType::Uint8Array - | types::DataType::Uint16Array - | types::DataType::Uint32Array - | types::DataType::Uint64Array - | types::DataType::FloatArray - | types::DataType::DoubleArray => try_from_json_value(value, data_type), - } - } - None => Ok(None), - } -} - -fn try_from_json_value( - value: Option, - data_type: &types::DataType, -) -> Result, Error> { - match value { - Some(value) => match data_type { - types::DataType::String => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::String(value))) - .map_err(|err| err.into()), - types::DataType::Bool => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Bool(value))) - .map_err(|err| err.into()), - types::DataType::Int8 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Int32(value.into()))) - .map_err(|err| err.into()), - types::DataType::Int16 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Int32(value.into()))) - .map_err(|err| err.into()), - types::DataType::Int32 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Int32(value))) - .map_err(|err| err.into()), - types::DataType::Int64 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Int64(value))) - .map_err(|err| err.into()), - types::DataType::Uint8 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Uint32(value.into()))) - .map_err(|err| err.into()), - types::DataType::Uint16 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Uint32(value.into()))) - .map_err(|err| err.into()), - types::DataType::Uint32 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Uint32(value))) - .map_err(|err| err.into()), - types::DataType::Uint64 => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Uint64(value))) - .map_err(|err| err.into()), - types::DataType::Float => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Float(value))) - .map_err(|err| err.into()), - types::DataType::Double => serde_json::from_value::(value) - .map(|value| Some(types::DataValue::Double(value))) - .map_err(|err| err.into()), - types::DataType::StringArray => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::StringArray(array))) - .map_err(|err| err.into()), - types::DataType::BoolArray => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::BoolArray(array))) - .map_err(|err| err.into()), - types::DataType::Int8Array => serde_json::from_value::>(value) - .map(|array| { - Some(types::DataValue::Int32Array( - array.iter().map(|value| (*value).into()).collect(), - )) - }) - .map_err(|err| err.into()), - types::DataType::Int16Array => serde_json::from_value::>(value) - .map(|array| { - Some(types::DataValue::Int32Array( - array.iter().map(|value| (*value).into()).collect(), - )) - }) - .map_err(|err| err.into()), - types::DataType::Int32Array => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::Int32Array(array))) - .map_err(|err| err.into()), - types::DataType::Int64Array => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::Int64Array(array))) - .map_err(|err| err.into()), - types::DataType::Uint8Array => serde_json::from_value::>(value) - .map(|array| { - Some(types::DataValue::Uint32Array( - array.iter().map(|value| (*value).into()).collect(), - )) - }) - .map_err(|err| err.into()), - types::DataType::Uint16Array => serde_json::from_value::>(value) - .map(|array| { - Some(types::DataValue::Uint32Array( - array.iter().map(|value| (*value).into()).collect(), - )) - }) - .map_err(|err| err.into()), - types::DataType::Uint32Array => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::Uint32Array(array))) - .map_err(|err| err.into()), - types::DataType::Uint64Array => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::Uint64Array(array))) - .map_err(|err| err.into()), - types::DataType::FloatArray => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::FloatArray(array))) - .map_err(|err| err.into()), - types::DataType::DoubleArray => serde_json::from_value::>(value) - .map(|array| Some(types::DataValue::DoubleArray(array))) - .map_err(|err| err.into()), - }, - None => Ok(None), - } -} - -fn flatten_vss_tree(root: RootEntry) -> Result, Error> { - let mut entries = BTreeMap::new(); - - for (path, entry) in root.0 { - add_entry(&mut entries, path, entry)?; - } - Ok(entries) -} - -fn add_entry( - entries: &mut BTreeMap, - path: String, - entry: Entry, -) -> Result<(), Error> { - match entry.entry_type { - EntryType::Branch => match entry.children { - Some(children) => { - for (name, child) in children { - add_entry(entries, format!("{path}.{name}"), child)?; - } - Ok(()) - } - None => Err(Error::ParseError( - "children required for type branch".to_owned(), - )), - }, - EntryType::Actuator => { - let data_type = match entry.data_type { - Some(data_type) => data_type.into(), - None => { - return Err(Error::ParseError( - "data_type required for actuator".to_owned(), - )) - } - }; - let _ = entries.insert( - path, - DataEntry { - entry_type: types::EntryType::Actuator, - change_type: determine_change_type( - entry.change_type, - types::EntryType::Actuator, - ), - description: entry.description, - comment: entry.comment, - unit: entry.unit, - min: try_from_json_value(entry.min, &data_type)?, - max: try_from_json_value(entry.max, &data_type)?, - allowed: try_from_json_array(entry.allowed, &data_type)?, - default: None, // isn't used by actuators - data_type, - }, - ); - Ok(()) - } - EntryType::Attribute => { - let data_type = match entry.data_type { - Some(data_type) => data_type.into(), - None => { - return Err(Error::ParseError( - "data_type required for actuator".to_owned(), - )) - } - }; - let _ = entries.insert( - path, - DataEntry { - entry_type: types::EntryType::Attribute, - description: entry.description, - comment: entry.comment, - unit: entry.unit, - min: try_from_json_value(entry.min, &data_type)?, - max: try_from_json_value(entry.max, &data_type)?, - allowed: try_from_json_array(entry.allowed, &data_type)?, - default: try_from_json_value(entry.default, &data_type)?, - change_type: determine_change_type( - entry.change_type, - types::EntryType::Attribute, - ), - data_type, - }, - ); - Ok(()) - } - EntryType::Sensor => { - let data_type = match entry.data_type { - Some(data_type) => data_type.into(), - None => { - return Err(Error::ParseError( - "data_type required for actuator".to_owned(), - )) - } - }; - let _ = entries.insert( - path, - DataEntry { - entry_type: types::EntryType::Sensor, - description: entry.description, - comment: entry.comment, - unit: entry.unit, - min: try_from_json_value(entry.min, &data_type)?, - max: try_from_json_value(entry.max, &data_type)?, - allowed: try_from_json_array(entry.allowed, &data_type)?, - change_type: determine_change_type(entry.change_type, types::EntryType::Sensor), - default: None, // isn't used by sensors - data_type, - }, - ); - Ok(()) - } - } -} - -fn determine_change_type( - change_type: Option, - entry_type: types::EntryType, -) -> types::ChangeType { - match change_type { - Some(ct) => match ct { - ChangeType::Continuous => types::ChangeType::Continuous, - ChangeType::OnChange => types::ChangeType::OnChange, - ChangeType::Static => types::ChangeType::Static, - }, - None => { - //As a default return Continous Change type for sensors and actuators and static for attributes - match entry_type { - types::EntryType::Attribute => types::ChangeType::Static, - _ => types::ChangeType::Continuous, - } - } - } -} - -pub fn parse_vss_from_reader(reader: R) -> Result, Error> -where - R: std::io::Read, -{ - let root_entry = match serde_json::from_reader::(reader) { - Ok(root_entry) => root_entry, - Err(err) => return Err(err.into()), - }; - - flatten_vss_tree(root_entry) -} - -pub fn parse_vss_from_str(data: &str) -> Result, Error> { - let root_entry = match serde_json::from_str::(data) { - Ok(root_entry) => root_entry, - Err(err) => return Err(err.into()), - }; - - flatten_vss_tree(root_entry) -} - -#[test] -fn test_parse_vss() { - let data = r#" -{ - "Vehicle": { - "children": { - "ADAS": { - "children": { - "ESC": { - "children": { - "IsEnabled": { - "datatype": "boolean", - "description": "Indicates if ESC is enabled. True = Enabled. False = Disabled.", - "type": "actuator", - "uuid": "3f4f39b8d8c05c97a6de685282ba74b7" - }, - "IsEngaged": { - "datatype": "boolean", - "description": "Indicates if ESC is currently regulating vehicle stability. True = Engaged. False = Not Engaged.", - "type": "sensor", - "uuid": "2088953a28385353a9d46b3a3dc11cac" - }, - "RoadFriction": { - "children": { - "MostProbable": { - "datatype": "float", - "description": "Most probable road friction, as calculated by the ESC system. Exact meaning of most probable is implementation specific. 0 = no friction, 100 = maximum friction.", - "max": 100, - "min": 0, - "type": "sensor", - "unit": "percent", - "uuid": "b0eb72430cd95bfbba0d187fcb6e2a62" - } - }, - "description": "Road friction values reported by the ESC system.", - "type": "branch", - "uuid": "71a32e4eb131532c82195508d93807ed" - } - }, - "description": "Electronic Stability Control System signals.", - "type": "branch", - "uuid": "636b4586ce7854b4b270a2f3b6c0af4f" - }, - "SupportedAutonomyLevel": { - "allowed": [ - "SAE_0", - "SAE_1", - "SAE_2", - "SAE_3", - "SAE_4", - "SAE_5" - ], - "datatype": "string", - "description": "Indicates the highest level of autonomy according to SAE J3016 taxonomy the vehicle is capable of.", - "type": "attribute", - "uuid": "020410189ab4517cb85ceda268b40f51" - } - }, - "description": "All Advanced Driver Assist Systems data.", - "type": "branch", - "uuid": "14c2b2e1297b513197d320a5ce58f42e" - }, - "MaxTowWeight": { - "datatype": "uint16", - "default": 1000, - "description": "Maximum weight of trailer.", - "type": "attribute", - "unit": "kg", - "uuid": "a1b8fd65897654aa8a418bccf443f1f3" - } - }, - "description": "High-level vehicle data.", - "type": "branch", - "uuid": "ccc825f94139544dbb5f4bfd033bece6" - } -}"#; - - let root_entry = match serde_json::from_str::(data) { - Ok(root_entry) => root_entry, - Err(err) => panic!("{}", err), - }; - - match flatten_vss_tree(root_entry) { - Ok(entries) => { - assert_eq!(entries.len(), 5); - match entries.get("Vehicle.ADAS.ESC.IsEnabled") { - Some(entry) => { - assert_eq!(entry.data_type, types::DataType::Bool); - assert_eq!(entry.entry_type, types::EntryType::Actuator); - assert_eq!( - entry.description, - "Indicates if ESC is enabled. True = Enabled. False = Disabled." - ); - } - None => panic!("Vehicle.ADAS.ESC.IsEnabled expected"), - } - match entries.get("Vehicle.ADAS.ESC.IsEngaged") { - Some(entry) => { - assert_eq!(entry.data_type, types::DataType::Bool); - assert_eq!(entry.entry_type, types::EntryType::Sensor); - } - None => panic!("Vehicle.ADAS.ESC.IsEngaged expected"), - } - - match entries.get("Vehicle.ADAS.ESC.RoadFriction.MostProbable") { - Some(entry) => { - assert_eq!(entry.data_type, types::DataType::Float); - assert_eq!(entry.entry_type, types::EntryType::Sensor); - assert_eq!(entry.min, Some(types::DataValue::Float(0.0))); - assert_eq!(entry.max, Some(types::DataValue::Float(100.0))); - assert_eq!(entry.unit, Some("percent".to_owned())); - } - None => panic!("Vehicle.ADAS.ESC.RoadFriction.MostProbable expected"), - } - - match entries.get("Vehicle.MaxTowWeight") { - Some(entry) => { - assert_eq!(entry.data_type, types::DataType::Uint16); - assert_eq!(entry.entry_type, types::EntryType::Attribute); - assert_eq!(entry.default, Some(types::DataValue::Uint32(1000))); - assert_eq!(entry.unit, Some("kg".to_owned())); - } - None => panic!("Vehicle.ADAS.ESC.RoadFriction.MostProbable expected"), - } - - match entries.get("Vehicle.ADAS.SupportedAutonomyLevel") { - Some(entry) => { - assert_eq!(entry.data_type, types::DataType::String); - assert_eq!(entry.entry_type, types::EntryType::Attribute); - match &entry.allowed { - Some(allowed) => match allowed { - types::DataValue::StringArray(array) => { - assert_eq!(array.len(), 6); - assert_eq!(array[0], "SAE_0"); - assert_eq!(array[1], "SAE_1"); - assert_eq!(array[2], "SAE_2"); - assert_eq!(array[3], "SAE_3"); - assert_eq!(array[4], "SAE_4"); - assert_eq!(array[5], "SAE_5"); - } - _ => panic!("allowed expected to be of type StringArray()"), - }, - None => panic!("allowed expected to be Some(...)"), - } - } - None => panic!("Vehicle.ADAS.SupportedAutonomyLevel expected"), - } - } - Err(err) => panic!("Expected parsing to work: {:?}", err), - } -} diff --git a/kuksa_databroker/databroker/tests/features/read_write_values.feature b/kuksa_databroker/databroker/tests/features/read_write_values.feature deleted file mode 100644 index a49a85812..000000000 --- a/kuksa_databroker/databroker/tests/features/read_write_values.feature +++ /dev/null @@ -1,180 +0,0 @@ -Feature: Reading and writing values of a VSS Data Entry - - Rule: Access with right permissions succeeds and fails with wrong/no permissions - - Background: - Given a running Databroker server with authorization enabled with the following Data Entries registered - | path | data type | change type | type | - | Vehicle.Speed | float | Static | Sensor | - | Vehicle.ADAS.ABS.IsEnabled | bool | Static | Actuator | - - Scenario: Writing the current value of an unset Data Entry without authenticating fails - When a client sets the current value of Vehicle.Width of type float to 13.4 - Then the operation fails with status code 16 - - Scenario: Read the current value of an unset Data Entry without authenticating fails - When a client gets the current value of Vehicle.Width - Then the operation fails with status code 16 - - Scenario: Writing the current value of a Data Entry without right permissions fails - When a client uses a token with scope read - And a client sets the current value of Vehicle.Speed of type float to 13.4 - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the current value of a Data Entry without right permissions fails - When a client uses a token with scope actuate - And a client sets the current value of Vehicle.Speed of type float to 13.4 - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the current value of a Data Entry without right permissions fails - When a client uses a token with scope provide:Vehicle.ADAS.ABS.IsEnabled - And a client sets the current value of Vehicle.Speed of type float to 13.4 - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the current value of a Data Entry with right permissions succeeds - When a client uses a token with scope provide:Vehicle.Speed - And a client sets the current value of Vehicle.Speed of type float to 13.4 - Then the set operation succeeds - - Scenario: Writing the target value of a Data Entry without right permissions fails - When a client uses a token with scope read - And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the target value of a Data Entry without right permissions fails - When a client uses a token with scope provide - And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the target value of a Data Entry without right permissions fails - When a client uses a token with scope actuate:Vehicle.Speed - And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true - Then setting the value for Vehicle.Speed fails with error code 403 - - Scenario: Writing the target value of a Data Entry with right permissions succeeds - When a client uses a token with scope actuate:Vehicle.ADAS.ABS.IsEnabled - And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true - Then the set operation succeeds - - Rule: Accessing unregistered Data Entries fails - - Background: - Given a running Databroker server with authorization disabled - - Scenario: Setting the current value of an unregistered Data Entry fails - When a client sets the current value of No.Such.Path of type float to 13.4 - Then setting the value for No.Such.Path fails with error code 404 - - Scenario: Reading the current value of an unregistered Data Entry fails - When a client gets the current value of No.Such.Path - Then the current value is not found - - Scenario: Setting the target value of an unregistered Data Entry fails - When a client sets the target value of No.Such.Path of type float to 13.4 - Then setting the value for No.Such.Path fails with error code 404 - - Scenario: Reading the target value of an unregistered Data Entry fails - When a client gets the target value of No.Such.Path - Then the target value is not found - - Rule: Target values can only be set on Actuators - - Background: - Given a running Databroker server with authorization disabled with the following Data Entries registered - | path | data type | change type | type | - | Vehicle.Powertrain.Range | uint32 | Continuous | Sensor | - | Vehicle.Width | uint16 | Static | Attribute | - - Scenario: Setting the target value of an Attribute fails - When a client sets the target value of Vehicle.Width of type uint16 to 13 - Then the operation fails with status code 3 - - Scenario: Setting the target value of a Sensor fails - When a client sets the target value of Vehicle.Powertrain.Range of type uint32 to 13455 - Then the operation fails with status code 3 - - Rule: Accessing registered Data Entries works - - Background: - Given a running Databroker server with authorization disabled with the following Data Entries registered - | path | data type | change type | type | - | Vehicle.Cabin.Lights.AmbientLight | uint8 | OnChange | Actuator | - | Vehicle.Cabin.Sunroof.Position | int8 | OnChange | Actuator | - | Vehicle.CurrentLocation.Longitude | double | Continuous | Sensor | - | Vehicle.IsMoving | bool | OnChange | Sensor | - | Vehicle.Powertrain.ElectricMotor.Power | int16 | Continuous | Sensor | - | Vehicle.Powertrain.ElectricMotor.Speed | int32 | Continuous | Sensor | - | Vehicle.Powertrain.Range | uint32 | Continuous | Sensor | - | Vehicle.Speed | float | Continuous | Sensor | - | Vehicle.TraveledDistanceHighRes | uint64 | Continuous | Sensor | - | Vehicle.Width | uint16 | Static | Attribute | - - Scenario: Reading the current value of an unset Data Entry yields an empty result - When a client gets the current value of Vehicle.Width - Then the current value for Vehicle.Width is not specified - - Scenario Outline: Reading the current value works - Given a Data Entry of type having current value - When a client gets the current value of - Then the current value for is having type - - Examples: - | path | type | value | - | Vehicle.Cabin.Sunroof.Position | int8 | -128 | - | Vehicle.Powertrain.ElectricMotor.Power | int16 | -32768 | - | Vehicle.Powertrain.ElectricMotor.Speed | int32 | -2147483648 | - | Vehicle.Cabin.Lights.AmbientLight | uint8 | 255 | - | Vehicle.Width | uint16 | 65535 | - | Vehicle.Powertrain.Range | uint32 | 4294967295 | - | Vehicle.TraveledDistanceHighRes | uint64 | 23425462462563924 | - | Vehicle.CurrentLocation.Longitude | double | 145.023544 | - | Vehicle.Speed | float | 45.5 | - | Vehicle.IsMoving | bool | true | - - Scenario Outline: Setting a Data Entry's current value using a wrong type fails - When a client sets the current value of Vehicle.Speed of type to - Then setting the value for Vehicle.Speed fails with error code 400 - - Examples: - | type | value | - | bool | true | - | double | 145.023544 | - | uint8 | 15 | - | uint16 | 13648 | - | uint32 | 4294967295 | - | uint64 | 24234543543535354 | - | int8 | -35 | - | int16 | -7295 | - | int32 | -2552565 | - | int64 | -255256525864925 | - - Scenario: Reading the target value of an unset Data Entry yields an empty result - When a client gets the target value of Vehicle.Cabin.Sunroof.Position - Then the target value for Vehicle.Cabin.Sunroof.Position is not specified - - Scenario Outline: Reading the target value of Actuators works - Given a Data Entry of type having target value - When a client gets the target value of - Then the target value for is having type - - Examples: - | path | type | value | - | Vehicle.Cabin.Lights.AmbientLight | uint8 | 255 | - | Vehicle.Cabin.Sunroof.Position | int8 | -128 | - - Scenario Outline: Setting an Actuator's target value using a wrong type fails - When a client sets the target value of Vehicle.Cabin.Sunroof.Position of type to - Then setting the value for Vehicle.Cabin.Sunroof.Position fails with error code 400 - - Examples: - | type | value | - | bool | true | - | double | -285625145.023544 | - | float | 145.023544 | - | uint8 | 15 | - | uint16 | 13648 | - | uint32 | 4294967295 | - | uint64 | 24234543543535354 | - | int16 | -7295 | - | int32 | -2552565 | - | int64 | -255256525864925 | diff --git a/kuksa_databroker/databroker/tests/read_write_values.rs b/kuksa_databroker/databroker/tests/read_write_values.rs deleted file mode 100644 index b127d6733..000000000 --- a/kuksa_databroker/databroker/tests/read_write_values.rs +++ /dev/null @@ -1,281 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -use core::panic; -use std::{collections::HashMap, future, time::SystemTime, vec}; - -use cucumber::{cli, gherkin::Step, given, then, when, writer, World as _}; -use databroker::broker; -use databroker_proto::kuksa::val::v1::{datapoint::Value, DataType, Datapoint}; -use tracing::debug; -use world::{DataBrokerWorld, ValueType}; - -mod world; - -fn get_data_entries_from_table( - step: &Step, -) -> Vec<( - String, - broker::DataType, - broker::ChangeType, - broker::EntryType, -)> { - let mut data_entries = vec![]; - if let Some(table) = step.table.as_ref() { - for row in table.rows.iter().skip(1) { - // skip header - let path = row[0].clone(); - let data_type_string = row[1].to_lowercase(); - let data_type = match data_type_string.as_str() { - "bool" => broker::DataType::Bool, - "double" => broker::DataType::Double, - "float" => broker::DataType::Float, - "int8" => broker::DataType::Int8, - "int16" => broker::DataType::Int16, - "int32" => broker::DataType::Int32, - "uint8" => broker::DataType::Uint8, - "uint16" => broker::DataType::Uint16, - "uint32" => broker::DataType::Uint32, - "uint64" => broker::DataType::Uint64, - _ => panic!( - "data type {} is not (yet) supported by this step implementation", - data_type_string - ), - }; - let change_type_string = row[2].to_lowercase(); - let change_type = match change_type_string.as_str() { - "onchange" => broker::ChangeType::OnChange, - "continuous" => broker::ChangeType::Continuous, - "static" => broker::ChangeType::Static, - _ => panic!("unsupported change type: {}", change_type_string), - }; - let entry_type_string = row[3].to_lowercase(); - let entry_type = match entry_type_string.as_str() { - "actuator" => broker::EntryType::Actuator, - "attribute" => broker::EntryType::Attribute, - "sensor" => broker::EntryType::Sensor, - _ => panic!("unsupported entry type: {}", entry_type_string), - }; - data_entries.push((path, data_type, change_type, entry_type)); - } - } - data_entries -} - -#[given(regex = "^a running Databroker server with authorization (enabled|disabled).*$")] -async fn start_databroker_server(w: &mut DataBrokerWorld, auth: String, step: &Step) { - let authorization_enabled: bool; - if auth == "enabled" { - authorization_enabled = true; - } else if auth == "disabled" { - authorization_enabled = false; - } else { - panic!("Not a known authorization keyword use enabled/disabled!") - } - - w.start_databroker(get_data_entries_from_table(step), authorization_enabled) - .await; - assert!(w.broker_client.is_some()) -} - -#[given(expr = "a Data Entry {word} of type {word} having {word} value {word}")] -async fn a_known_data_entry_has_value( - w: &mut DataBrokerWorld, - path: String, - data_type: DataType, - value_type: ValueType, - value: String, -) { - set_value(w, value_type, path, data_type, value).await; - w.assert_set_succeeded() -} - -#[when(expr = "a client uses a token with scope {word}")] -async fn authorize_client(w: &mut DataBrokerWorld, scope: String) { - let token = w.create_token(scope); - w.broker_client - .as_mut() - .and_then(|client| match client.basic_client.set_access_token(token) { - Ok(()) => Some(client), - Err(e) => { - println!("Error: {e}"); - None - } - }) - .expect("no Databroker client available, broker not started?"); -} - -#[when(expr = "a client sets the {word} value of {word} of type {word} to {word}")] -async fn set_value( - w: &mut DataBrokerWorld, - value_type: ValueType, - path: String, - data_type: DataType, - value: String, -) { - let client = w - .broker_client - .as_mut() - .expect("no Databroker client available, broker not started?"); - let value = Value::new(data_type, value.as_str()).expect("cannot parse value into given type"); - let datapoint = Datapoint { - timestamp: Some(SystemTime::now().into()), - value: Some(value), - }; - - match value_type { - ValueType::Target => { - match client - .set_target_values(HashMap::from([(path.clone(), datapoint.clone())])) - .await - { - Ok(_) => { - w.current_client_error = None; - } - Err(e) => { - debug!("failed to invoke Databroker's set operation: {:?}", e); - w.current_client_error = Some(e); - } - } - } - ValueType::Current => { - match client - .set_current_values(HashMap::from([(path.clone(), datapoint.clone())])) - .await - { - Ok(_) => { - w.current_client_error = None; - } - Err(e) => { - debug!("failed to invoke Databroker's set operation: {:?}", e); - w.current_client_error = Some(e); - } - } - } - } -} - -#[when(expr = "a client gets the {word} value of {word}")] -async fn get_value(w: &mut DataBrokerWorld, value_type: ValueType, path: String) { - let client = w - .broker_client - .as_mut() - .expect("no Databroker client available, broker not started?"); - match value_type { - ValueType::Target => match client.get_target_values(vec![&path]).await { - Ok(res) => w.current_data_entries = Some(res), - Err(e) => { - debug!("failed to invoke Databroker's get operation: {:?}", e); - w.current_client_error = Some(e); - } - }, - ValueType::Current => match client.get_current_values(vec![path]).await { - Ok(res) => w.current_data_entries = Some(res), - Err(e) => { - debug!("failed to invoke Databroker's get operation: {:?}", e); - w.current_client_error = Some(e); - } - }, - } -} - -#[then(expr = "the {word} value for {word} is {word} having type {word}")] -fn assert_value( - w: &mut DataBrokerWorld, - value_type: ValueType, - path: String, - expected_value: String, - expected_type: DataType, -) { - match w.get_current_data_entry(path.clone()) { - Some(data_entry) => { - let data_point = match value_type { - ValueType::Current => data_entry.value.clone(), - ValueType::Target => data_entry.actuator_target.clone(), - }; - match data_point.and_then(|dp| dp.value) { - Some(actual_value) => { - let expected_value = Value::new(expected_type, expected_value.as_str()) - .expect("unsupported data type"); - assert_eq!(actual_value, expected_value) - } - None => panic!("no current/target value for path: {:?}", path), - }; - match data_entry - .metadata - .and_then(|m| DataType::from_i32(m.data_type)) - { - None => panic!("no metadata for path: {:?}", path), - Some(actual_type) => assert_eq!(actual_type, expected_type), - }; - } - None => panic!( - "failed to retrieve entry for path {:?} from Databroker response", - path - ), - } -} - -#[then(expr = "the {word} value for {word} is not specified")] -fn assert_value_is_unspecified(w: &mut DataBrokerWorld, value_type: ValueType, path: String) { - let value = match value_type { - ValueType::Current => w.get_current_value(path), - ValueType::Target => w.get_target_value(path), - }; - assert!(value.is_none()) -} - -#[then(regex = r"^the (current|target) value is not found$")] -fn assert_value_not_found(w: &mut DataBrokerWorld) { - w.assert_response_has_error_code(vec![404]); -} - -#[then(expr = "setting the value for {word} fails with error code {int}")] -fn assert_set_request_failure(w: &mut DataBrokerWorld, _path: String, expected_error_code: u32) { - w.assert_response_has_error_code(vec![expected_error_code]) -} - -/// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc -#[then(expr = "the operation fails with status code {int}")] -fn assert_request_failure(w: &mut DataBrokerWorld, expected_status_code: i32) { - w.assert_status_has_code(expected_status_code) -} - -#[then(expr = "the set operation succeeds")] -fn assert_set_succeeds(w: &mut DataBrokerWorld) { - w.assert_set_succeeded() -} - -#[tokio::main] -async fn main() { - // databroker::init_logging(); - - let opts = cli::Opts::<_, _, _, world::UnsupportedLibtestArgs>::parsed(); - if let Some(thread_count) = opts.custom.test_threads { - println!("Ignoring command line parameter \"--test-threads {thread_count}\" passed in by test runner"); - } - - DataBrokerWorld::cucumber() - .fail_on_skipped() - // support "--format json" argument being passed into test - .with_writer(writer::Normalize::new(writer::Libtest::or_basic())) - .with_cli(opts) - .after(|_feature, _rule, _scenario, _ev, world| { - if let Some(w) = world { - w.stop_databroker(); - } - Box::pin(future::ready(())) - }) - .run_and_exit("tests/features/read_write_values.feature") - .await; -} diff --git a/kuksa_databroker/databroker/tests/world/mod.rs b/kuksa_databroker/databroker/tests/world/mod.rs deleted file mode 100644 index 798a142f2..000000000 --- a/kuksa_databroker/databroker/tests/world/mod.rs +++ /dev/null @@ -1,401 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::{ - future::poll_fn, - net::SocketAddr, - str::FromStr, - sync::{Arc, Mutex}, - task::{Poll, Waker}, -}; - -use chrono::Utc; -use jsonwebtoken::{encode, Algorithm, EncodingKey, Header}; - -use databroker_proto::kuksa::val::v1::{datapoint::Value, DataEntry}; -use kuksa_common::ClientError; - -use databroker::{ - broker, - grpc::{self, server::ServerTLS}, - permissions, -}; - -use tokio::net::TcpListener; -use tracing::debug; - -use lazy_static::lazy_static; - -use tonic::transport::{Certificate, ClientTlsConfig, Identity}; -use tonic::Code; - -#[cfg(feature = "tls")] -lazy_static! { - pub static ref CERTS: DataBrokerCertificates = DataBrokerCertificates::new(); -} - -#[derive(clap::Args)] // re-export of `clap::Args` -pub struct UnsupportedLibtestArgs { - // allow "--test-threads" parameter being passed into the test - #[arg(long)] - pub test_threads: Option, -} - -#[derive(Debug, Default)] -pub enum ValueType { - #[default] - Current, - Target, -} - -#[derive(Debug, serde::Serialize)] -struct Token { - sub: String, - iss: String, - aud: Vec, - iat: i64, - exp: i64, - scope: String, -} - -impl FromStr for ValueType { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(match s.to_lowercase().as_str() { - "current" => Self::Current, - "target" => Self::Target, - invalid => return Err(format!("Invalid `ValueType`: {invalid}")), - }) - } -} - -#[cfg(feature = "tls")] -pub struct DataBrokerCertificates { - server_identity: Identity, - ca_certs: Certificate, - private_key: String, - public_key: String, -} - -#[cfg(feature = "tls")] -impl DataBrokerCertificates { - fn new() -> Self { - let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let cert_dir = format!("{manifest_dir}/../../kuksa_certificates"); - debug!("reading key material from {}", cert_dir); - let key_file = format!("{cert_dir}/Server.key"); - let server_key = std::fs::read(key_file).expect("could not read server key"); - let cert_file = format!("{cert_dir}/Server.pem"); - let server_cert = std::fs::read(cert_file).expect("could not read server certificate"); - let server_identity = tonic::transport::Identity::from_pem(server_cert, server_key); - let ca_file = format!("{cert_dir}/CA.pem"); - let ca_store = std::fs::read(ca_file).expect("could not read root CA file"); - let ca_certs = Certificate::from_pem(ca_store); - let private_key_file = format!("{cert_dir}/jwt/jwt.key"); - let private_key: String = - std::fs::read_to_string(private_key_file).expect("could not read private key file"); - let public_key_file = format!("{cert_dir}/jwt/jwt.key.pub"); - let public_key: String = - std::fs::read_to_string(public_key_file).expect("could not read public key file"); - DataBrokerCertificates { - server_identity, - ca_certs, - private_key, - public_key, - } - } - - fn server_tls_config(&self) -> ServerTLS { - ServerTLS::Enabled { - tls_config: tonic::transport::ServerTlsConfig::new() - .identity(self.server_identity.clone()), - } - } - - fn client_tls_config(&self) -> ClientTlsConfig { - ClientTlsConfig::new().ca_certificate(self.ca_certs.clone()) - } -} - -#[derive(Debug)] -struct DataBrokerState { - running: bool, - address: Option, - waker: Option, -} - -#[derive(cucumber::World, Debug)] -#[world(init = Self::new)] -pub struct DataBrokerWorld { - pub current_data_entries: Option>, - pub current_client_error: Option, - pub broker_client: Option, - data_broker_state: Arc>, -} - -impl DataBrokerWorld { - pub fn new() -> DataBrokerWorld { - DataBrokerWorld { - current_data_entries: Some(vec![]), - current_client_error: None, - data_broker_state: Arc::new(Mutex::new(DataBrokerState { - running: false, - address: None, - waker: None, - })), - broker_client: None, - } - } - - pub async fn start_databroker( - &mut self, - data_entries: Vec<( - String, - broker::DataType, - broker::ChangeType, - broker::EntryType, - )>, - authorization_enabled: bool, - ) { - { - let state = self - .data_broker_state - .lock() - .expect("failed to lock shared broker state"); - if state.running { - if state.address.is_some() { - return; - } else { - panic!("Databroker seems to be running but listener address is unknown") - } - } - } - let owned_state = self.data_broker_state.to_owned(); - let listener = TcpListener::bind("127.0.0.1:0") - .await - .expect("failed to bind to socket"); - let addr = listener - .local_addr() - .expect("failed to determine listener's port"); - - tokio::spawn(async move { - let version = option_env!("VERGEN_GIT_SEMVER_LIGHTWEIGHT") - .unwrap_or(option_env!("VERGEN_GIT_SHA").unwrap_or("unknown")); - let data_broker = broker::DataBroker::new(version); - let database = data_broker.authorized_access(&permissions::ALLOW_ALL); - for (name, data_type, change_type, entry_type) in data_entries { - if let Err(_error) = database - .add_entry( - name, - data_type, - change_type, - entry_type, - "N/A".to_string(), - None, - None, - ) - .await - { - return Err("failed to register metadata for {name}"); - } - } - - { - let mut state = owned_state.lock().unwrap(); - state.running = true; - state.address = Some(addr); - } - - let mut _authorization = databroker::authorization::Authorization::Disabled; - - if authorization_enabled { - // public key comes from kuksa.val/kuksa_certificates/jwt/jwt.key.pub - match databroker::authorization::Authorization::new(CERTS.public_key.clone()) { - Ok(auth) => _authorization = auth, - Err(e) => println!("Error: {e}"), - } - } - - grpc::server::serve_with_incoming_shutdown( - listener, - data_broker, - #[cfg(feature = "tls")] - CERTS.server_tls_config(), - _authorization, - poll_fn(|cx| { - let mut state = owned_state - .lock() - .expect("failed to lock shared broker state"); - if state.running { - debug!("Databroker is still running"); - state.waker = Some(cx.waker().clone()); - Poll::Pending - } else { - // println!("Databroker has been stopped"); - Poll::Ready(()) - } - }), - ) - .await - .map_err(|e| { - debug!("failed to start Databroker: {e}"); - { - let mut state = owned_state - .lock() - .expect("failed to lock shared broker state"); - state.running = false; - state.address = None; - } - "error" - }) - .map(|_| { - debug!("Databroker has been stopped"); - }) - }); - - debug!("started Databroker [address: {addr}]"); - - let data_broker_url = format!("http://{}:{}", addr.ip(), addr.port()); - - self.broker_client = match kuksa_common::to_uri(data_broker_url.clone()) { - Ok(uri) => Some(kuksa::KuksaClient::new(uri)), - Err(e) => { - println!("Error connecting to {data_broker_url}: {e}"); - None - } - }; - - #[cfg(feature = "tls")] - if let Some(client) = self.broker_client.as_mut() { - client - .basic_client - .set_tls_config(CERTS.client_tls_config()); - } - } - - pub fn stop_databroker(&mut self) { - debug!("stopping Databroker"); - let mut state = self - .data_broker_state - .lock() - .expect("failed to lock shared broker state"); - state.running = false; - if let Some(waker) = state.waker.take() { - waker.wake() - }; - self.broker_client = None - } - - pub fn get_current_data_entry(&self, path: String) -> Option { - self.current_data_entries - .clone() - .and_then(|res| res.into_iter().find(|data_entry| data_entry.path == path)) - } - - pub fn get_current_value(&self, path: String) -> Option { - self.get_current_data_entry(path) - .and_then(|data_entry| data_entry.value) - .and_then(|datapoint| datapoint.value) - } - - pub fn get_target_value(&self, path: String) -> Option { - self.get_current_data_entry(path) - .and_then(|data_entry| data_entry.actuator_target) - .and_then(|datapoint| datapoint.value) - } - - /// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc - pub fn assert_status_has_code(&self, expected_status_code: i32) { - match &self.current_client_error { - Some(ClientError::Connection(_)) => panic!("Connection error shall not occur"), - Some(ClientError::Function(_)) => { - panic!("Fucntion has an error that shall not occur") - } - Some(ClientError::Status(status)) => { - assert_eq!(status.code(), Code::from_i32(expected_status_code)) - } - None => panic!("No error, but an errror is expected"), - } - } - - pub fn assert_response_has_error_code(&self, error_codes: Vec) { - let mut code = Vec::new(); - - if let Some(client_error) = self.current_client_error.clone() { - match client_error { - ClientError::Connection(_) => panic!("response contains connection error"), - ClientError::Function(e) => { - for element in e { - if !code.contains(&element.code) { - code.push(element.code) - } - } - } - ClientError::Status(_) => panic!("response contains channel error"), - } - - assert!( - !code.is_empty(), - "response contains no error code {:?}", - code - ); - assert_eq!(code, error_codes, "response contains unexpected error code"); - } else { - panic!("response contains no error code"); - } - } - - pub fn assert_set_succeeded(&self) { - if let Some(error) = self.current_client_error.clone() { - match error { - ClientError::Connection(e) => { - panic!("No connection error {:?} should occcur", e) - } - ClientError::Function(e) => { - panic!("No function error {:?} should occur", e) - } - ClientError::Status(status) => { - panic!("No status error {:?} should occur", status) - } - } - } - } - - pub fn create_token(&self, scope: String) -> String { - let datetime = Utc::now(); - let timestamp = datetime.timestamp(); - let timestamp_exp = (match datetime.checked_add_months(chrono::Months::new(24)) { - None => panic!("couldn't add 2 years"), - Some(date) => date, - }) - .timestamp(); - // Your payload as a Rust struct or any serializable type - let payload = Token { - sub: "test dev".to_string(), - iss: "integration test instance".to_string(), - aud: vec!["kuksa.val".to_string()], - iat: timestamp, - exp: timestamp_exp, - scope, - }; - - // Create an encoding key from the private key - let encoding_key = EncodingKey::from_rsa_pem(CERTS.private_key.clone().as_bytes()) - .expect("Failed to create encoding key"); - - // Encode the payload using RS256 algorithm - encode(&Header::new(Algorithm::RS256), &payload, &encoding_key) - .expect("Failed to encode JWT") - } -} diff --git a/kuksa_databroker/doc/QUERY.md b/kuksa_databroker/doc/QUERY.md deleted file mode 100644 index c2a9c3a0e..000000000 --- a/kuksa_databroker/doc/QUERY.md +++ /dev/null @@ -1,266 +0,0 @@ -# 1. Data Broker Query Syntax - -- [1. Data Broker Query Syntax](#1-data-broker-query-syntax) - - [1.1. Intro](#11-intro) - - [1.2. Subscribe to single datapoint with a single condition](#12-subscribe-to-single-datapoint-with-a-single-condition) - - [1.2.1. Time / conceptual row view](#121-time--conceptual-row-view) - - [1.2.2. Responses](#122-responses) - - [1.3. Subscribing to multiple data points / signals](#13-subscribing-to-multiple-data-points--signals) - - [1.3.1. Responses](#131-responses) - - [1.4. Returning multiple signals and a condition](#14-returning-multiple-signals-and-a-condition) - - [1.4.1. Responses](#141-responses) -- [2. Future](#2-future) - - [2.1. Introduce LAG() function,](#21-introduce-lag-function) - - [2.1.1. Time / conceptual row view](#211-time--conceptual-row-view) - - [2.1.2. Responses](#212-responses) - - [2.2. React on condition changes](#22-react-on-condition-changes) - - [2.2.1. Time / conceptual row view](#221-time--conceptual-row-view) - - [2.2.2. Responses](#222-responses) - -## 1.1. Intro -This document describes the behaviour of the current implementation. - -The query syntax is a subset of SQL and is used to select which data -points (or conditional expressions) are to be returned if the WHERE clause -evaluates to true. - - -## 1.2. Subscribe to single datapoint with a single condition - -Subscribe to: -```sql -SELECT - Vehicle.Seats.Row1.Position -WHERE - Vehicle.Datapoint2 > 50 -``` - -Get a response every time `Vehicle.Seats.Row1.Position` or -`Vehicle.Datapoint2` is updated (and the condition is true) - -### 1.2.1. Time / conceptual row view - -Each time any datapoint changes a new "conceptual row" is created. -It contains the values of all datapoints at that point in time. - - -| #| ...Datapoint1 | ...Datapoint2 | ...Row1.Position | Response | | -|-:|:-------------:|:-------------:|:----------------:|----------|:--| -| 1| 15 | 30 | 250 | | Query posted, nothing is returned since (`Vehicle.Datapoint2 > 50`) isn't true | -| 2| 20* | 30 | 250 | | | -| 3| 20 | 30 | 240* | | | -| 4| 20 | 40* | 240 | | | -| 5| 20 | 40 | 230* | | | -| 6| 23 | 60* | 230 | #1 | (`Vehicle.Datapoint2 > 50`) turns true | -| 7| 23 | 61* | 230 | #2 | `Vehicle.Datapoint2` changed | -| 8| 21* | 61 | 230 | | | -| 9| 21 | 61 | 220* | #3 | `Vehicle.Seats.Row1.Position` changed | -|10| 21 | 62* | 220 | #4 | `Vehicle.Datapoint2` changed | -|11| 21 | 62 | 210* | #5 | `Vehicle.Datapoint2` changed | - -### 1.2.2. Responses -| | Vehicle.Seats.Row1.Position | -|-:|:---------------------------:| -| 1| 230 | -| 2| 230 | -| 3| 220 | -| 4| 220 | -| 5| 210 | - -## 1.3. Subscribing to multiple data points / signals - -Using a single condition and in this examples using `AS` to name -the response fields. - -Subscribe to: -```sql -SELECT - Vehicle.Seats.Row1.Position AS pos1, - Vehicle.Seats.Row2.Position AS pos2 -WHERE - Vehicle.Datapoint2 > 50 -``` - -A message is received every time `Vehicle.Seats.Row1.Position`, `Vehicle.Seats.Row2.Position` or `Vehicle.Datapoint2` is updated (and the condition is true) - - -| #| ...Datapoint2 | ...Row1.Position | ...Row2.Position |Response | | -|-:|:-------------:|:----------------:|:----------------:|---------|:--| -| 1| 30 | 250 | 150 | | Query posted, nothing is returned since (`Vehicle.Datapoint2 > 50`) isn't true | -| 2| 30 | 250 | 150 | | | -| 3| 30 | 240* | 150 | | | -| 4| 30 | 240 | 160* | | | -| 5| 40* | 240 | 160 | | | -| 6| 60* | 240 | 160 | #1 | (`Vehicle.Datapoint2 > 50`) turns true | -| 7| 61* | 240 | 160 | #2 | `Vehicle.Datapoint2` changed | -| 8| 61 | 240 | 160 | | (some unrelated signal changed) | -| 9| 61 | 240 | 180* | #3 | `Vehicle.Seats.Row2.Position` changed | -|10| 62* | 240 | 180 | #4 | `Vehicle.Datapoint2` changed | -|11| 62 | 230* | 180 | #5 | `Vehicle.Seats.Row2.Position` changed | - -### 1.3.1. Responses -| | pos1 | pos2 | -|-:|:----:|:----:| -| 1| 240 | 160 | -| 2| 240 | 160 | -| 3| 240 | 180 | -| 4| 240 | 180 | -| 5| 230 | 180 | - -## 1.4. Returning multiple signals and a condition - -Conditions are possible to select (and name) as well. - -Subscribe to: -```sql -SELECT - Vehicle.Seats.Row1.Position AS pos1, - Vehicle.Seats.Row2.Position AS pos2, - (Vehicle.Speed = 0) AS cond1 -WHERE - Vehicle.Datapoint2 BETWEEN 50 AND 150 - AND - Vehicle.Seats.Row1.Position > 100 -``` - -A message is received every time `Vehicle.Seats.Row1.Position`, `Vehicle.Seats.Row2.Position` or -`Vehicle.Datapoint2` is updated (and the condition is true) - - -| #| ...Datapoint2 | pos1 | pos2 | ..Speed | Response | | -|-:|:-------------:|:----:|:----:|---------|:----------|:---| -| 1| 30 | 250 | 150 | 30 | | Query posted, nothing is returned since (`Vehicle.Datapoint2 > 50`) isn't true | -| 2| 30 | 250 | 150 | 30 | | | -| 3| 30 | 240* | 150 | 30 | | | -| 4| 30 | 240 | 160* | 30 | | | -| 5| 40* | 240 | 160 | 30 | | | -| 6| 60* | 240 | 160 | 30 | #1 | (`Vehicle.Datapoint2 > 50`) turns true | -| 7| 61* | 240 | 160 | 30 | #2 | `Vehicle.Datapoint2` changed | -| 8| 61 | 240 | 160 | 20 | | (some unrelated signal changed) | -| 9| 61 | 240 | 180* | 10 | #3 | `Vehicle.Seats.Row2.Position` changed | -|10| 61 | 240 | 180 | 0* | #4 | `Vehicle.Speed` changed dependent cond1 | -|11| 61 | 230* | 180 | 0 | #5 | `Vehicle.Seats.Row2.Position` changed | - - -### 1.4.1. Responses -| | pos1 |pos2 | cond1 | -|-:|:----:|:---:|:-------:| -| 1| 240 | 160 | `false` | -| 2| 240 | 160 | `false` | -| 3| 240 | 180 | `false` | -| 4| 240 | 180 | `true` | -| 5| 230 | 180 | `true` | - -# 2. Future - -What follows isn't implemented or fully thought through yet. - -``` - _____ _ _ _____ _ _ ____ _____ -| ___| | | |_ _| | | | _ \| ____| -| |_ | | | | | | | | | | |_) | _| -| _| | |_| | | | | |_| | _ <| |___ -|_| \___/ |_| \___/|_| \_\_____| - - / BRAINSTORMING FOLLOWS -``` - -## 2.1. Introduce LAG() function, - -Implement and use the `LAG()` function to be able to match current values with values from the past. - -This can be used to only receive updates if `Vehicle.Seats.Row1.Position` actually -changes (and the original condition is met). - -Subscribe to: -```sql -SELECT - Vehicle.Seats.Row1.Position -WHERE - Vehicle.Seats.Row1.Position <> LAG(Vehicle.Seats.Row1.Position) - AND - Vehicle.Datapoint2 > 50 -``` - -Get a response every time `Vehicle.Seats.Row1.Position` is changed (and the condition is true). - -### 2.1.1. Time / conceptual row view - -| #| ...Datapoint1 | ...Datapoint2 | ...Row1.Position | Response | | -|-:|:-------------:|:-------------:|:----------------:|:--------:|:--| -| 1| 15* | 30 | 250 | | Condition not fulfilled, nothing initially returned| -| 2| 20 | 30* | 250 | || -| 3| 20 | 30 | 240* | || -| 4| 20 | 40* | 240 | || -| 5| 20 | 40 | 230* | || -| 6| 23 | 60* | 230 | #1|`Vehicle.Datapoint2 > 50` turns true | -| 7| 23 | 61* | 230 | || -| 8| 21* | 61 | 230 | || -| 9| 21 | 61 | 220* | #2|`Vehicle.Seats.Row1.Position` changed| -|10| 21 | 62* | 220 | || -|11| 21 | 62 | 210* | #3|`Vehicle.Seats.Row1.Position` changed| - -### 2.1.2. Responses -| | Vehicle.Seats.Row1.Position | -|-:|:---------------------------:| -| 1| 230 | -| 2| 220 | -| 3| 210 | - -## 2.2. React on condition changes - - Example with two additional conditions, using the - the `LAG()` function to only send updates if `Vehicle.Seats.Row1.Position` - changes (and the condition is met). - The result includes the evaluation of the condition, named `cond` in this case, - in the projection (the SELECT statement). - - This gives the client: - 1. An initial response even when the condition isn't - met, along with an easy way to tell this is the case - (by checking if cond == true) - 2. A notification when the condition is no longer met. - -```sql -SELECT - Vehicle.Seats.Row1.Position AS pos, -- current position - (Vehicle.Datapoint2 > 50) AS cond -- cond -WHERE - ( -- send update if condition is met & position is updated - Vehicle.Seats.Row1.Position <> LAG(pos) - AND - (Vehicle.Datapoint2 > 50) - ) - OR - ( -- Also send update if condition changes - (Vehicle.Datapoint2 > 50) <> LAG((Vehicle.Datapoint2 > 50)) - ) -``` - -### 2.2.1. Time / conceptual row view - -| #| ...Datapoint1 | ...Datapoint2 | ...Row1.Position | Response | | -|-:|:-------------:|:-------------:|:----------------:|:--------:|:--| -|1 | *15 | 30 | 250 | #1 | | -|2 | 20 | *30 | 250 | | | -|3 | 20 | 30 | *240 | | | -|4 | 20 | *40 | 240 | | | -|5 | 20 | 40 | *230 | | | -|6 | 23 | *60 | 230 | #2 | | -|7 | 23 | *61 | 230 | | | -|8 | *21 | 61 | 230 | | | -|9 | 21 | 61 | *220 | #3 | | -|10| 21 | *62 | 220 | | | -|11| 21 | 62 | *210 | #4 | | -|12| 21 | *55 | 210 | | | -|13| 21 | *49 | 210 | #5 | | - - -### 2.2.2. Responses -| | pos | cond | -|-:|:---:|:-----:| -| 1| 250 |`false`| -| 2| 230 | `true`| -| 3| 220 | `true`| -| 4| 220 | `true`| -| 5| 210 |`false`| diff --git a/kuksa_databroker/doc/TYPES.md b/kuksa_databroker/doc/TYPES.md deleted file mode 100644 index 2e25de4ca..000000000 --- a/kuksa_databroker/doc/TYPES.md +++ /dev/null @@ -1,40 +0,0 @@ -# Mapping data types - -This is how [VSS data types](https://covesa.github.io/vehicle_signal_specification/rule_set/data_entry/data_types/) -defined by [COVESA VSS](https://covesa.github.io/vehicle_signal_specification/) are mapped to the data types used by -the GRPC interface of the Vehicle Data Broker (VDB). - -The GRPC interface uses [protobuf](https://developers.google.com/protocol-buffers/docs/proto3#scalar) to serialize the data and provides metadata to describes the data types - -See `enum DataType` in [types.proto](../proto/kuksa/val/v1/types.proto) for the data types and `value` in `Datapoint` for for what is actually sent on the wire. - -**Note:** Support for timestamps are currently not implemented (except for setting it as the data type). - -| VSS data type | VDB metadata (`DataType`) | serialized as `value` | -|---------------|:--------------------------|----------------------:| -| string | STRING | string (protobuf) | -| boolean | BOOL | bool (protobuf) | -| int8 | INT8 | sint32 (protobuf) | -| int16 | INT16 | sint32 (protobuf) | -| int32 | INT32 | sint32 (protobuf) | -| int64 | INT64 | sint64 (protobuf) | -| uint8 | UINT8 | uint32 (protobuf) | -| uint16 | UINT16 | uint32 (protobuf) | -| uint32 | UINT32 | uint32 (protobuf) | -| uint64 | UINT64 | uint64 (protobuf) | -| float | FLOAT | float (protobuf) | -| double | DOUBLE | double (protobuf) | -| timestamp | TIMESTAMP | - | -| string[] | STRING_ARRAY | - | -| bool[] | BOOL_ARRAY | - | -| int8[] | INT8_ARRAY | - | -| int16[] | INT16_ARRAY | - | -| int32[] | INT32_ARRAY | - | -| int64[] | INT64_ARRAY | - | -| uint8[] | UINT8_ARRAY | - | -| uint16[] | UINT16_ARRAY | - | -| uint32[] | UINT32_ARRAY | - | -| uint64[] | UINT64_ARRAY | - | -| float[] | FLOAT_ARRAY | - | -| double[] | DOUBLE_ARRAY | - | -| timestamp[] | TIMESTAMP_ARRAY | - | \ No newline at end of file diff --git a/kuksa_databroker/doc/behavior.md b/kuksa_databroker/doc/behavior.md deleted file mode 100644 index bee5441f5..000000000 --- a/kuksa_databroker/doc/behavior.md +++ /dev/null @@ -1,4 +0,0 @@ -# Runtime behavior and potential attacks -The implementation of KUKSA databroker shall represent the latest value of a ```Datapoint```. Therefore the databroker always sets a ```timestamp``` for a ```Datapoint```. This means if a new value comes in it overwrites the older value. We opted for this behavior because a actuator/provider/application can have no access to a system time. For some use cases it could be interesting to provide a timestamp set by the actuator/provider/application. For this we added a so called source timestamp (short ```source_ts```) to the ```Datapoint``` class. This source timestamp is optional and per default set to None. - -If an attacker gets an authorized connection to the databroker he can set the source_timestamp and overwrite the value with a new one. But for this he/she needs read and write access through JWT tokens. If a provider decides to work with ```source_ts``` of a ```Datapoint``` than it should be clear that they can be false/outdated. diff --git a/kuksa_databroker/doc/user_guide.md b/kuksa_databroker/doc/user_guide.md deleted file mode 100644 index 1d82e58c2..000000000 --- a/kuksa_databroker/doc/user_guide.md +++ /dev/null @@ -1,263 +0,0 @@ - - -# Eclipse Kuksa.val™ Databroker User Guide - -The following sections provide information for running and configuring Databroker as well as information necessary for developing client applications invoking Databroker's external API. - - -
- Table of Contents -
    -
  1. Getting Help
  2. -
  3. Running Databroker
  4. -
  5. Enabling Authorization
  6. -
  7. Enabling TLS
  8. -
  9. Query Syntax
  10. -
  11. Using Custom VSS Data Entries
  12. -
  13. Configuration Reference
  14. -
  15. Signal Change Types
  16. -
  17. API
  18. -
  19. Known Limitations
  20. -
-
- -## Getting help - -Get help, options and version number with: - -```sh -docker run --rm -it ghcr.io/eclipse/kuksa.val/databroker:master -h -``` -```console -Usage: databroker [OPTIONS] - -Options: - --address Bind address [env: KUKSA_DATA_BROKER_ADDR=] [default: 127.0.0.1] - --port Bind port [env: KUKSA_DATA_BROKER_PORT=] [default: 55555] - --vss Populate data broker with VSS metadata from (comma-separated) list of files [env: KUKSA_DATA_BROKER_METADATA_FILE=] - --jwt-public-key Public key used to verify JWT access tokens - --disable-authorization Disable authorization - --insecure Allow insecure connections - --tls-cert TLS certificate file (.pem) - --tls-private-key TLS private key file (.key) - -h, --help Print help - -V, --version Print version -``` - -

(back to top)

- -## Running Databroker - -Before starting Databroker you must decide if you want to use TLS for incoming connections or not. It is recommended to use TLS which is enabled by providing a private key with `--tls-private-key` and a server certificate with `--tls-cert`. If you do not provide those options, Databroker will only accept insecure connections. The default behavior may change in the future, so if you want insecure connections it is recommended to use the `--insecure` argument. - -```sh -docker run --rm -it -p 55555:55555 ghcr.io/eclipse/kuksa.val/databroker:master --insecure -``` - -> :warning: **Warning**: Default port not working on Mac OS -> -> On several versions of Mac OS applications cannot bind to port `55555`. Databroker needs to be configured to bind to a different (local) port in such cases: -> -> ```sh -> docker run --rm -it -p 55556:55555 ghcr.io/eclipse/kuksa.val/databroker:master --insecure -> ``` -> -> Please refer to [this support forum post](https://developer.apple.com/forums/thread/671197) for additional information. - -

(back to top)

- -## Enabling Authorization - -Kuksa.val Databroker supports authorizing client requests based on JSON Web Tokens (JWT) provided by clients in request messages. This requires configuration of a PEM file containing the public key that should be used for verifying the tokens' signature. - -The Kuksa.val repository contains example keys and JWTs in the *kuksa_certificates* and *jwt* folders respectively which can be used for testing purposes. In order to run the commands below, the repository first needs to be cloned to the local file system: - -```shell -git clone https://github.com/eclipse/kuksa.val.git -``` - -The Databroker can then be started with support for authorization from the repository root folder: - -```shell -# in repository root -docker run --rm -it --name Server --network kuksa -v ./kuksa_certificates:/opt/kuksa ghcr.io/eclipse/kuksa.val/databroker:master --insecure --jwt-public-key /opt/kuksa/jwt/jwt.key.pub -``` - -The CLI can then be configured to use a corresponding token when connecting to the Databroker: - -```shell -# in repository root -docker run --rm -it --network kuksa -v ./jwt:/opt/kuksa ghcr.io/eclipse/kuksa.val/databroker-cli:master --server Server:55555 --token-file /opt/kuksa/read-vehicle-speed.token -``` - -The token contains a claim that authorizes the client to read the *Vehicle.Speed* signal only. -Consequently, checking if the vehicle cabin's dome light is switched on fails: - -```sh -get Vehicle.Cabin.Light.IsDomeOn -``` -```console -[get] OK -Vehicle.Cabin.Light.IsDomeOn: ( AccessDenied ) -``` - -Retrieving the vehicle's current speed succeeds but yields no value because no value has been set yet: - -```sh -get Vehicle.Speed -``` -```console -[get] OK -Vehicle.Speed: ( NotAvailable ) -``` -

(back to top)

- -## Enabling TLS - -Kuksa.val Databroker also supports using TLS for encrypting the traffic with clients. This requires configuration of both a PEM file containing the server's private key as well as a PEM file containing the server's X.509 certificate. - -The command below starts the Databroker using the example key and certificate from the Kuksa.val repository: - -```sh -# in repository root -docker run --rm -it --name Server --network kuksa -v ./kuksa_certificates:/opt/kuksa ghcr.io/eclipse/kuksa.val/databroker:master --tls-cert /opt/kuksa/Server.pem --tls-private-key /opt/kuksa/Server.key -``` - -The CLI can then be configured to use a corresponding trusted CA certificate store when connecting to the Databroker: - -```shell -# in repository root -docker run --rm -it --network kuksa -v ./kuksa_certificates:/opt/kuksa ghcr.io/eclipse/kuksa.val/databroker-cli:master --server Server:55555 --ca-cert /opt/kuksa/CA.pem -``` -

(back to top)

- -## Query Syntax - -Clients can subscribe to updates of data entries of interest using an SQL-based [query syntax](./QUERY.md). - -You can try it out using the `subscribe` command in the client: - -```shell -subscribe -SELECT - Vehicle.ADAS.ABS.IsError -WHERE - Vehicle.ADAS.ABS.IsEngaged -``` - -```console -[subscribe] OK -Subscription is now running in the background. Received data is identified by [1]. -``` -

(back to top)

- -## Using Custom VSS Data Entries - -Kuksa.val Databroker supports management of data entries and branches as defined by the [Vehicle Signal Specification](https://covesa.github.io/vehicle_signal_specification/). - -In order to generate metadata from a VSS specification that can be loaded by the data broker, it's possible to use the `vspec2json.py` tool -that's available in the [vss-tools](https://github.com/COVESA/vss-tools) repository: - -```shell -./vss-tools/vspec2json.py -I spec spec/VehicleSignalSpecification.vspec vss.json -``` - -The Databroker can be configured to load the resulting `vss.json` file at startup: - -```shell -docker run --rm -it -p 55555:55555 ghcr.io/eclipse/kuksa.val/databroker:master --insecure --vss vss.json -``` -

(back to top)

- -## Signal Change Types - -Internally, databroker knows different change types for VSS signals. There are three change-types - - - **Continuous**: This are usually sensor values that are continuous, such as vehicle speed. Whenever a continuous signal is updated by a provider, all subscribers are notified. - - **OnChange**: This are usually signals that indicate a state, for example whether a door is open or closed. Even if this data is updated regularly by a provider, subscribers are only notified if the the value actually changed. - - **Static**: This are signals that you would not expect to change during one ignition cycle, i.e. if an application reads it once, it could expect this signal to remain static during the runtime of the application. The VIN might be an example for a static signal. Currently, in the implementation subscribing `static` signals behaves exactly the same as `onchange` signals. - -Currently the way signals are classified depends on databroker version. - -Up until version 0.4.1 (including) - - All signals where registered as **OnChange** - -Starting from version 0.4.2, if nothing else is specified - - All signals that are of VSS type `sensor` or `actuator` are registered as change type `continuous` - - All attributes are registered as change type `static` - -VSS itself has no concept of change types, but you can explicitly configure this behavior on vss level with the custom extended attribute `x-kuksa-changetype`, where valid values are `continuous`, `onchange`, `static`. - -Check these `.vspec` snippets as example - -```yaml -VehicleIdentification.VIN: - datatype: string - type: attribute - x-kuksa-changetype: static - description: 17-character Vehicle Identification Number (VIN) as defined by ISO 3779. - -Vehicle.Speed: - datatype: float - type: sensor - unit: km/h - x-kuksa-changetype: continuous - description: Vehicle speed. - -Vehicle.Cabin.Door.Row1.Left.IsOpen: - datatype: boolean - type: actuator - x-kuksa-changetype: onchange - description: Is door open or closed -``` - -The change types currently apply on *current* values, when subscribing to a *target value*, as an actuation provider would do, any set on the target value is propagated just like in `continuous` mode, even if a datapoint (and thus its current value behavior) is set to `onchange` or `static`. The idea here is, that a "set" by an application is the intent to actuate something (maybe a retry even), and should thus always be forwarded to the provider. - - -## Configuration Reference - -The default configuration can be overridden by means of setting the corresponding environment variables and/or providing options on the command line as illustrated in the previous sections. - -| CLI option | Environment Variable | Default Value | Description | -|---------------------|-----------------------------------|---------------|-------------| -|`--vss`,
`--metadata`| `KUKSA_DATA_BROKER_METADATA_FILE` | | Populate data broker with metadata from file | -|`--address` | `KUKSA_DATA_BROKER_ADDR` | `127.0.0.1` | Listen for rpc calls | -|`--port` | `KUKSA_DATA_BROKER_PORT` | `55555` | Listen for rpc calls | -|`--jwt-public-key` | | | Public key used to verify JWT access tokens | -|`--tls-cert` | | | TLS certificate file (.pem) | -|`--tls-private-key` | | | TLS private key file (.key) | -|`--insecure` | | | Allow insecure connections (default unless `--tls-cert` and `--tls-private-key` options are provided) | - -

(back to top)

- -## API - -Kuksa.val Databroker provides [gRPC](https://grpc.io/) based API endpoints which can be used by -clients to interact with the server. - -gRPC services are specified by means of `.proto` files which define the services and the data -exchanged between server and client. - -[Tooling](https://grpc.io/docs/languages/) is available for most popular programming languages to create -client stubs for invoking the services. - -The Databroker uses gRPC's default HTTP/2 transport and [protocol buffers](https://developers.google.com/protocol-buffers) for message serialization. -The same `.proto` file can be used to generate server skeleton and client stubs for other transports and serialization formats as well. - -HTTP/2 is a binary replacement for HTTP/1.1 used for handling connections, multiplexing (channels) and providing a standardized way to add headers for authorization and TLS for encryption/authentication. -It also supports bi-directional streaming between client and server. - -Kuksa.val Databroker implements the following service interfaces: - -* [kuksa.val.v1.VAL](../databroker-proto/proto/kuksa/val/v1/val.proto) -* [sdv.databroker.v1.Broker](../databroker-proto/proto/sdv/databroker/v1/broker.proto) -* [sdv.databroker.v1.Collector](../databroker-proto/proto/sdv/databroker/v1/collector.proto) - -

(back to top)

- -## Known Limitations - -* Arrays are not supported in conditions as part of queries (i.e. in the WHERE clause). -* Arrays are not supported by the CLI (except for displaying them) - -

(back to top)

diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.py deleted file mode 100644 index 98dc94a86..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.py +++ /dev/null @@ -1,114 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: sdv/databroker/v1/broker.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from gen_proto.sdv.databroker.v1 import types_pb2 as sdv_dot_databroker_dot_v1_dot_types__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1esdv/databroker/v1/broker.proto\x12\x11sdv.databroker.v1\x1a\x1dsdv/databroker/v1/types.proto\"*\n\x14GetDatapointsRequest\x12\x12\n\ndatapoints\x18\x01 \x03(\t\"\xb0\x01\n\x12GetDatapointsReply\x12I\n\ndatapoints\x18\x01 \x03(\x0b\x32\x35.sdv.databroker.v1.GetDatapointsReply.DatapointsEntry\x1aO\n\x0f\x44\x61tapointsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1c.sdv.databroker.v1.Datapoint:\x02\x38\x01\"!\n\x10SubscribeRequest\x12\r\n\x05query\x18\x02 \x01(\t\"\x9c\x01\n\x0eSubscribeReply\x12=\n\x06\x66ields\x18\x01 \x03(\x0b\x32-.sdv.databroker.v1.SubscribeReply.FieldsEntry\x1aK\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1c.sdv.databroker.v1.Datapoint:\x02\x38\x01\"#\n\x12GetMetadataRequest\x12\r\n\x05names\x18\x01 \x03(\t\"=\n\x10GetMetadataReply\x12)\n\x04list\x18\x01 \x03(\x0b\x32\x1b.sdv.databroker.v1.Metadata2\x9b\x02\n\x06\x42roker\x12_\n\rGetDatapoints\x12\'.sdv.databroker.v1.GetDatapointsRequest\x1a%.sdv.databroker.v1.GetDatapointsReply\x12U\n\tSubscribe\x12#.sdv.databroker.v1.SubscribeRequest\x1a!.sdv.databroker.v1.SubscribeReply0\x01\x12Y\n\x0bGetMetadata\x12%.sdv.databroker.v1.GetMetadataRequest\x1a#.sdv.databroker.v1.GetMetadataReplyb\x06proto3') - - - -_GETDATAPOINTSREQUEST = DESCRIPTOR.message_types_by_name['GetDatapointsRequest'] -_GETDATAPOINTSREPLY = DESCRIPTOR.message_types_by_name['GetDatapointsReply'] -_GETDATAPOINTSREPLY_DATAPOINTSENTRY = _GETDATAPOINTSREPLY.nested_types_by_name['DatapointsEntry'] -_SUBSCRIBEREQUEST = DESCRIPTOR.message_types_by_name['SubscribeRequest'] -_SUBSCRIBEREPLY = DESCRIPTOR.message_types_by_name['SubscribeReply'] -_SUBSCRIBEREPLY_FIELDSENTRY = _SUBSCRIBEREPLY.nested_types_by_name['FieldsEntry'] -_GETMETADATAREQUEST = DESCRIPTOR.message_types_by_name['GetMetadataRequest'] -_GETMETADATAREPLY = DESCRIPTOR.message_types_by_name['GetMetadataReply'] -GetDatapointsRequest = _reflection.GeneratedProtocolMessageType('GetDatapointsRequest', (_message.Message,), { - 'DESCRIPTOR' : _GETDATAPOINTSREQUEST, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.GetDatapointsRequest) - }) -_sym_db.RegisterMessage(GetDatapointsRequest) - -GetDatapointsReply = _reflection.GeneratedProtocolMessageType('GetDatapointsReply', (_message.Message,), { - - 'DatapointsEntry' : _reflection.GeneratedProtocolMessageType('DatapointsEntry', (_message.Message,), { - 'DESCRIPTOR' : _GETDATAPOINTSREPLY_DATAPOINTSENTRY, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.GetDatapointsReply.DatapointsEntry) - }) - , - 'DESCRIPTOR' : _GETDATAPOINTSREPLY, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.GetDatapointsReply) - }) -_sym_db.RegisterMessage(GetDatapointsReply) -_sym_db.RegisterMessage(GetDatapointsReply.DatapointsEntry) - -SubscribeRequest = _reflection.GeneratedProtocolMessageType('SubscribeRequest', (_message.Message,), { - 'DESCRIPTOR' : _SUBSCRIBEREQUEST, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.SubscribeRequest) - }) -_sym_db.RegisterMessage(SubscribeRequest) - -SubscribeReply = _reflection.GeneratedProtocolMessageType('SubscribeReply', (_message.Message,), { - - 'FieldsEntry' : _reflection.GeneratedProtocolMessageType('FieldsEntry', (_message.Message,), { - 'DESCRIPTOR' : _SUBSCRIBEREPLY_FIELDSENTRY, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.SubscribeReply.FieldsEntry) - }) - , - 'DESCRIPTOR' : _SUBSCRIBEREPLY, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.SubscribeReply) - }) -_sym_db.RegisterMessage(SubscribeReply) -_sym_db.RegisterMessage(SubscribeReply.FieldsEntry) - -GetMetadataRequest = _reflection.GeneratedProtocolMessageType('GetMetadataRequest', (_message.Message,), { - 'DESCRIPTOR' : _GETMETADATAREQUEST, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.GetMetadataRequest) - }) -_sym_db.RegisterMessage(GetMetadataRequest) - -GetMetadataReply = _reflection.GeneratedProtocolMessageType('GetMetadataReply', (_message.Message,), { - 'DESCRIPTOR' : _GETMETADATAREPLY, - '__module__' : 'sdv.databroker.v1.broker_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.GetMetadataReply) - }) -_sym_db.RegisterMessage(GetMetadataReply) - -_BROKER = DESCRIPTOR.services_by_name['Broker'] -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _GETDATAPOINTSREPLY_DATAPOINTSENTRY._options = None - _GETDATAPOINTSREPLY_DATAPOINTSENTRY._serialized_options = b'8\001' - _SUBSCRIBEREPLY_FIELDSENTRY._options = None - _SUBSCRIBEREPLY_FIELDSENTRY._serialized_options = b'8\001' - _GETDATAPOINTSREQUEST._serialized_start=84 - _GETDATAPOINTSREQUEST._serialized_end=126 - _GETDATAPOINTSREPLY._serialized_start=129 - _GETDATAPOINTSREPLY._serialized_end=305 - _GETDATAPOINTSREPLY_DATAPOINTSENTRY._serialized_start=226 - _GETDATAPOINTSREPLY_DATAPOINTSENTRY._serialized_end=305 - _SUBSCRIBEREQUEST._serialized_start=307 - _SUBSCRIBEREQUEST._serialized_end=340 - _SUBSCRIBEREPLY._serialized_start=343 - _SUBSCRIBEREPLY._serialized_end=499 - _SUBSCRIBEREPLY_FIELDSENTRY._serialized_start=424 - _SUBSCRIBEREPLY_FIELDSENTRY._serialized_end=499 - _GETMETADATAREQUEST._serialized_start=501 - _GETMETADATAREQUEST._serialized_end=536 - _GETMETADATAREPLY._serialized_start=538 - _GETMETADATAREPLY._serialized_end=599 - _BROKER._serialized_start=602 - _BROKER._serialized_end=885 -# @@protoc_insertion_point(module_scope) diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.pyi b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.pyi deleted file mode 100644 index 0d0c4ee30..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2.pyi +++ /dev/null @@ -1,144 +0,0 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.message -import gen_proto.sdv.databroker.v1.types_pb2 -import typing -import typing_extensions - -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class GetDatapointsRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - DATAPOINTS_FIELD_NUMBER: builtins.int - @property - def datapoints(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: - """A list of requested data points.""" - pass - def __init__(self, - *, - datapoints: typing.Optional[typing.Iterable[typing.Text]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["datapoints",b"datapoints"]) -> None: ... -global___GetDatapointsRequest = GetDatapointsRequest - -class GetDatapointsReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class DatapointsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: typing.Text - @property - def value(self) -> sdv.databroker.v1.types_pb2.Datapoint: ... - def __init__(self, - *, - key: typing.Text = ..., - value: typing.Optional[sdv.databroker.v1.types_pb2.Datapoint] = ..., - ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - DATAPOINTS_FIELD_NUMBER: builtins.int - @property - def datapoints(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, sdv.databroker.v1.types_pb2.Datapoint]: - """Contains the values of the requested data points. - If a requested data point is not available, the corresponding Datapoint - will have the respective failure value set. - """ - pass - def __init__(self, - *, - datapoints: typing.Optional[typing.Mapping[typing.Text, sdv.databroker.v1.types_pb2.Datapoint]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["datapoints",b"datapoints"]) -> None: ... -global___GetDatapointsReply = GetDatapointsReply - -class SubscribeRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - QUERY_FIELD_NUMBER: builtins.int - query: typing.Text - """Subscribe to a set of data points (or expressions) described - by the provided query. - The query syntax is a subset of SQL and is described in more - detail in the QUERY.md file. - """ - - def __init__(self, - *, - query: typing.Text = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["query",b"query"]) -> None: ... -global___SubscribeRequest = SubscribeRequest - -class SubscribeReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class FieldsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: typing.Text - @property - def value(self) -> sdv.databroker.v1.types_pb2.Datapoint: ... - def __init__(self, - *, - key: typing.Text = ..., - value: typing.Optional[sdv.databroker.v1.types_pb2.Datapoint] = ..., - ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - FIELDS_FIELD_NUMBER: builtins.int - @property - def fields(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, sdv.databroker.v1.types_pb2.Datapoint]: - """Contains the fields specified by the query. - If a requested data point value is not available, the corresponding - Datapoint will have it's respective failure value set. - """ - pass - def __init__(self, - *, - fields: typing.Optional[typing.Mapping[typing.Text, sdv.databroker.v1.types_pb2.Datapoint]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["fields",b"fields"]) -> None: ... -global___SubscribeReply = SubscribeReply - -class GetMetadataRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - NAMES_FIELD_NUMBER: builtins.int - @property - def names(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: - """Request metadata for a list of data points referenced by their names. - e.g. "Vehicle.Cabin.Seat.Row1.Pos1.Position" or "Vehicle.Speed". - - If no names are provided, metadata for all known data points will be - returned. - """ - pass - def __init__(self, - *, - names: typing.Optional[typing.Iterable[typing.Text]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["names",b"names"]) -> None: ... -global___GetMetadataRequest = GetMetadataRequest - -class GetMetadataReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - LIST_FIELD_NUMBER: builtins.int - @property - def list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[sdv.databroker.v1.types_pb2.Metadata]: - """Contains metadata of the requested data points. If a data point - doesn't exist (i.e. not known to the Data Broker) the corresponding - Metadata isn't part of the returned list. - """ - pass - def __init__(self, - *, - list: typing.Optional[typing.Iterable[sdv.databroker.v1.types_pb2.Metadata]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["list",b"list"]) -> None: ... -global___GetMetadataReply = GetMetadataReply diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2_grpc.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2_grpc.py deleted file mode 100644 index 5c87db18a..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/broker_pb2_grpc.py +++ /dev/null @@ -1,146 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -from gen_proto.sdv.databroker.v1 import broker_pb2 as sdv_dot_databroker_dot_v1_dot_broker__pb2 - - -class BrokerStub(object): - """Missing associated documentation comment in .proto file.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.GetDatapoints = channel.unary_unary( - '/sdv.databroker.v1.Broker/GetDatapoints', - request_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsReply.FromString, - ) - self.Subscribe = channel.unary_stream( - '/sdv.databroker.v1.Broker/Subscribe', - request_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeReply.FromString, - ) - self.GetMetadata = channel.unary_unary( - '/sdv.databroker.v1.Broker/GetMetadata', - request_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataReply.FromString, - ) - - -class BrokerServicer(object): - """Missing associated documentation comment in .proto file.""" - - def GetDatapoints(self, request, context): - """Request a set of datapoints (values) - - Returns a list of requested data points. - - InvalidArgument is returned if the request is malformed. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def Subscribe(self, request, context): - """Subscribe to a set of data points or conditional expressions - using the Data Broker Query Syntax (described in QUERY.md) - - Returns a stream of replies. - - InvalidArgument is returned if the request is malformed. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetMetadata(self, request, context): - """Request the metadata of a set of datapoints - - Returns metadata of the requested data points that exist. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_BrokerServicer_to_server(servicer, server): - rpc_method_handlers = { - 'GetDatapoints': grpc.unary_unary_rpc_method_handler( - servicer.GetDatapoints, - request_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsReply.SerializeToString, - ), - 'Subscribe': grpc.unary_stream_rpc_method_handler( - servicer.Subscribe, - request_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeReply.SerializeToString, - ), - 'GetMetadata': grpc.unary_unary_rpc_method_handler( - servicer.GetMetadata, - request_deserializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataReply.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'sdv.databroker.v1.Broker', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) - - - # This class is part of an EXPERIMENTAL API. -class Broker(object): - """Missing associated documentation comment in .proto file.""" - - @staticmethod - def GetDatapoints(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/sdv.databroker.v1.Broker/GetDatapoints', - sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_broker__pb2.GetDatapointsReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def Subscribe(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/sdv.databroker.v1.Broker/Subscribe', - sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_broker__pb2.SubscribeReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def GetMetadata(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/sdv.databroker.v1.Broker/GetMetadata', - sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_broker__pb2.GetMetadataReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.py deleted file mode 100644 index 25d69dd4d..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: sdv/databroker/v1/collector.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from gen_proto.sdv.databroker.v1 import types_pb2 as sdv_dot_databroker_dot_v1_dot_types__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!sdv/databroker/v1/collector.proto\x12\x11sdv.databroker.v1\x1a\x1dsdv/databroker/v1/types.proto\"\xba\x01\n\x17UpdateDatapointsRequest\x12N\n\ndatapoints\x18\x01 \x03(\x0b\x32:.sdv.databroker.v1.UpdateDatapointsRequest.DatapointsEntry\x1aO\n\x0f\x44\x61tapointsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1c.sdv.databroker.v1.Datapoint:\x02\x38\x01\"\xaf\x01\n\x15UpdateDatapointsReply\x12\x44\n\x06\x65rrors\x18\x01 \x03(\x0b\x32\x34.sdv.databroker.v1.UpdateDatapointsReply.ErrorsEntry\x1aP\n\x0b\x45rrorsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x30\n\x05value\x18\x02 \x01(\x0e\x32!.sdv.databroker.v1.DatapointError:\x02\x38\x01\"\xba\x01\n\x17StreamDatapointsRequest\x12N\n\ndatapoints\x18\x01 \x03(\x0b\x32:.sdv.databroker.v1.StreamDatapointsRequest.DatapointsEntry\x1aO\n\x0f\x44\x61tapointsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1c.sdv.databroker.v1.Datapoint:\x02\x38\x01\"\xaf\x01\n\x15StreamDatapointsReply\x12\x44\n\x06\x65rrors\x18\x01 \x03(\x0b\x32\x34.sdv.databroker.v1.StreamDatapointsReply.ErrorsEntry\x1aP\n\x0b\x45rrorsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x30\n\x05value\x18\x02 \x01(\x0e\x32!.sdv.databroker.v1.DatapointError:\x02\x38\x01\"R\n\x19RegisterDatapointsRequest\x12\x35\n\x04list\x18\x01 \x03(\x0b\x32\'.sdv.databroker.v1.RegistrationMetadata\"\x9d\x01\n\x14RegistrationMetadata\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\tdata_type\x18\x02 \x01(\x0e\x32\x1b.sdv.databroker.v1.DataType\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x32\n\x0b\x63hange_type\x18\x04 \x01(\x0e\x32\x1d.sdv.databroker.v1.ChangeType\"\x93\x01\n\x17RegisterDatapointsReply\x12H\n\x07results\x18\x01 \x03(\x0b\x32\x37.sdv.databroker.v1.RegisterDatapointsReply.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x32\xd3\x02\n\tCollector\x12n\n\x12RegisterDatapoints\x12,.sdv.databroker.v1.RegisterDatapointsRequest\x1a*.sdv.databroker.v1.RegisterDatapointsReply\x12h\n\x10UpdateDatapoints\x12*.sdv.databroker.v1.UpdateDatapointsRequest\x1a(.sdv.databroker.v1.UpdateDatapointsReply\x12l\n\x10StreamDatapoints\x12*.sdv.databroker.v1.StreamDatapointsRequest\x1a(.sdv.databroker.v1.StreamDatapointsReply(\x01\x30\x01\x62\x06proto3') - - - -_UPDATEDATAPOINTSREQUEST = DESCRIPTOR.message_types_by_name['UpdateDatapointsRequest'] -_UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY = _UPDATEDATAPOINTSREQUEST.nested_types_by_name['DatapointsEntry'] -_UPDATEDATAPOINTSREPLY = DESCRIPTOR.message_types_by_name['UpdateDatapointsReply'] -_UPDATEDATAPOINTSREPLY_ERRORSENTRY = _UPDATEDATAPOINTSREPLY.nested_types_by_name['ErrorsEntry'] -_STREAMDATAPOINTSREQUEST = DESCRIPTOR.message_types_by_name['StreamDatapointsRequest'] -_STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY = _STREAMDATAPOINTSREQUEST.nested_types_by_name['DatapointsEntry'] -_STREAMDATAPOINTSREPLY = DESCRIPTOR.message_types_by_name['StreamDatapointsReply'] -_STREAMDATAPOINTSREPLY_ERRORSENTRY = _STREAMDATAPOINTSREPLY.nested_types_by_name['ErrorsEntry'] -_REGISTERDATAPOINTSREQUEST = DESCRIPTOR.message_types_by_name['RegisterDatapointsRequest'] -_REGISTRATIONMETADATA = DESCRIPTOR.message_types_by_name['RegistrationMetadata'] -_REGISTERDATAPOINTSREPLY = DESCRIPTOR.message_types_by_name['RegisterDatapointsReply'] -_REGISTERDATAPOINTSREPLY_RESULTSENTRY = _REGISTERDATAPOINTSREPLY.nested_types_by_name['ResultsEntry'] -UpdateDatapointsRequest = _reflection.GeneratedProtocolMessageType('UpdateDatapointsRequest', (_message.Message,), { - - 'DatapointsEntry' : _reflection.GeneratedProtocolMessageType('DatapointsEntry', (_message.Message,), { - 'DESCRIPTOR' : _UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.UpdateDatapointsRequest.DatapointsEntry) - }) - , - 'DESCRIPTOR' : _UPDATEDATAPOINTSREQUEST, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.UpdateDatapointsRequest) - }) -_sym_db.RegisterMessage(UpdateDatapointsRequest) -_sym_db.RegisterMessage(UpdateDatapointsRequest.DatapointsEntry) - -UpdateDatapointsReply = _reflection.GeneratedProtocolMessageType('UpdateDatapointsReply', (_message.Message,), { - - 'ErrorsEntry' : _reflection.GeneratedProtocolMessageType('ErrorsEntry', (_message.Message,), { - 'DESCRIPTOR' : _UPDATEDATAPOINTSREPLY_ERRORSENTRY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.UpdateDatapointsReply.ErrorsEntry) - }) - , - 'DESCRIPTOR' : _UPDATEDATAPOINTSREPLY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.UpdateDatapointsReply) - }) -_sym_db.RegisterMessage(UpdateDatapointsReply) -_sym_db.RegisterMessage(UpdateDatapointsReply.ErrorsEntry) - -StreamDatapointsRequest = _reflection.GeneratedProtocolMessageType('StreamDatapointsRequest', (_message.Message,), { - - 'DatapointsEntry' : _reflection.GeneratedProtocolMessageType('DatapointsEntry', (_message.Message,), { - 'DESCRIPTOR' : _STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.StreamDatapointsRequest.DatapointsEntry) - }) - , - 'DESCRIPTOR' : _STREAMDATAPOINTSREQUEST, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.StreamDatapointsRequest) - }) -_sym_db.RegisterMessage(StreamDatapointsRequest) -_sym_db.RegisterMessage(StreamDatapointsRequest.DatapointsEntry) - -StreamDatapointsReply = _reflection.GeneratedProtocolMessageType('StreamDatapointsReply', (_message.Message,), { - - 'ErrorsEntry' : _reflection.GeneratedProtocolMessageType('ErrorsEntry', (_message.Message,), { - 'DESCRIPTOR' : _STREAMDATAPOINTSREPLY_ERRORSENTRY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.StreamDatapointsReply.ErrorsEntry) - }) - , - 'DESCRIPTOR' : _STREAMDATAPOINTSREPLY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.StreamDatapointsReply) - }) -_sym_db.RegisterMessage(StreamDatapointsReply) -_sym_db.RegisterMessage(StreamDatapointsReply.ErrorsEntry) - -RegisterDatapointsRequest = _reflection.GeneratedProtocolMessageType('RegisterDatapointsRequest', (_message.Message,), { - 'DESCRIPTOR' : _REGISTERDATAPOINTSREQUEST, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.RegisterDatapointsRequest) - }) -_sym_db.RegisterMessage(RegisterDatapointsRequest) - -RegistrationMetadata = _reflection.GeneratedProtocolMessageType('RegistrationMetadata', (_message.Message,), { - 'DESCRIPTOR' : _REGISTRATIONMETADATA, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.RegistrationMetadata) - }) -_sym_db.RegisterMessage(RegistrationMetadata) - -RegisterDatapointsReply = _reflection.GeneratedProtocolMessageType('RegisterDatapointsReply', (_message.Message,), { - - 'ResultsEntry' : _reflection.GeneratedProtocolMessageType('ResultsEntry', (_message.Message,), { - 'DESCRIPTOR' : _REGISTERDATAPOINTSREPLY_RESULTSENTRY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.RegisterDatapointsReply.ResultsEntry) - }) - , - 'DESCRIPTOR' : _REGISTERDATAPOINTSREPLY, - '__module__' : 'sdv.databroker.v1.collector_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.RegisterDatapointsReply) - }) -_sym_db.RegisterMessage(RegisterDatapointsReply) -_sym_db.RegisterMessage(RegisterDatapointsReply.ResultsEntry) - -_COLLECTOR = DESCRIPTOR.services_by_name['Collector'] -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY._options = None - _UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_options = b'8\001' - _UPDATEDATAPOINTSREPLY_ERRORSENTRY._options = None - _UPDATEDATAPOINTSREPLY_ERRORSENTRY._serialized_options = b'8\001' - _STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY._options = None - _STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_options = b'8\001' - _STREAMDATAPOINTSREPLY_ERRORSENTRY._options = None - _STREAMDATAPOINTSREPLY_ERRORSENTRY._serialized_options = b'8\001' - _REGISTERDATAPOINTSREPLY_RESULTSENTRY._options = None - _REGISTERDATAPOINTSREPLY_RESULTSENTRY._serialized_options = b'8\001' - _UPDATEDATAPOINTSREQUEST._serialized_start=88 - _UPDATEDATAPOINTSREQUEST._serialized_end=274 - _UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_start=195 - _UPDATEDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_end=274 - _UPDATEDATAPOINTSREPLY._serialized_start=277 - _UPDATEDATAPOINTSREPLY._serialized_end=452 - _UPDATEDATAPOINTSREPLY_ERRORSENTRY._serialized_start=372 - _UPDATEDATAPOINTSREPLY_ERRORSENTRY._serialized_end=452 - _STREAMDATAPOINTSREQUEST._serialized_start=455 - _STREAMDATAPOINTSREQUEST._serialized_end=641 - _STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_start=195 - _STREAMDATAPOINTSREQUEST_DATAPOINTSENTRY._serialized_end=274 - _STREAMDATAPOINTSREPLY._serialized_start=644 - _STREAMDATAPOINTSREPLY._serialized_end=819 - _STREAMDATAPOINTSREPLY_ERRORSENTRY._serialized_start=372 - _STREAMDATAPOINTSREPLY_ERRORSENTRY._serialized_end=452 - _REGISTERDATAPOINTSREQUEST._serialized_start=821 - _REGISTERDATAPOINTSREQUEST._serialized_end=903 - _REGISTRATIONMETADATA._serialized_start=906 - _REGISTRATIONMETADATA._serialized_end=1063 - _REGISTERDATAPOINTSREPLY._serialized_start=1066 - _REGISTERDATAPOINTSREPLY._serialized_end=1213 - _REGISTERDATAPOINTSREPLY_RESULTSENTRY._serialized_start=1167 - _REGISTERDATAPOINTSREPLY_RESULTSENTRY._serialized_end=1213 - _COLLECTOR._serialized_start=1216 - _COLLECTOR._serialized_end=1555 -# @@protoc_insertion_point(module_scope) diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.pyi b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.pyi deleted file mode 100644 index 87265140f..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2.pyi +++ /dev/null @@ -1,184 +0,0 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.message -import gen_proto.sdv.databroker.v1.types_pb2 -import typing -import typing_extensions - -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class UpdateDatapointsRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class DatapointsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: builtins.int - @property - def value(self) -> sdv.databroker.v1.types_pb2.Datapoint: ... - def __init__(self, - *, - key: builtins.int = ..., - value: typing.Optional[sdv.databroker.v1.types_pb2.Datapoint] = ..., - ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - DATAPOINTS_FIELD_NUMBER: builtins.int - @property - def datapoints(self) -> google.protobuf.internal.containers.MessageMap[builtins.int, sdv.databroker.v1.types_pb2.Datapoint]: ... - def __init__(self, - *, - datapoints: typing.Optional[typing.Mapping[builtins.int, sdv.databroker.v1.types_pb2.Datapoint]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["datapoints",b"datapoints"]) -> None: ... -global___UpdateDatapointsRequest = UpdateDatapointsRequest - -class UpdateDatapointsReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class ErrorsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: builtins.int - value: sdv.databroker.v1.types_pb2.DatapointError.ValueType - def __init__(self, - *, - key: builtins.int = ..., - value: sdv.databroker.v1.types_pb2.DatapointError.ValueType = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - ERRORS_FIELD_NUMBER: builtins.int - @property - def errors(self) -> google.protobuf.internal.containers.ScalarMap[builtins.int, sdv.databroker.v1.types_pb2.DatapointError.ValueType]: - """If empty, everything went well""" - pass - def __init__(self, - *, - errors: typing.Optional[typing.Mapping[builtins.int, sdv.databroker.v1.types_pb2.DatapointError.ValueType]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["errors",b"errors"]) -> None: ... -global___UpdateDatapointsReply = UpdateDatapointsReply - -class StreamDatapointsRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class DatapointsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: builtins.int - @property - def value(self) -> sdv.databroker.v1.types_pb2.Datapoint: ... - def __init__(self, - *, - key: builtins.int = ..., - value: typing.Optional[sdv.databroker.v1.types_pb2.Datapoint] = ..., - ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - DATAPOINTS_FIELD_NUMBER: builtins.int - @property - def datapoints(self) -> google.protobuf.internal.containers.MessageMap[builtins.int, sdv.databroker.v1.types_pb2.Datapoint]: ... - def __init__(self, - *, - datapoints: typing.Optional[typing.Mapping[builtins.int, sdv.databroker.v1.types_pb2.Datapoint]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["datapoints",b"datapoints"]) -> None: ... -global___StreamDatapointsRequest = StreamDatapointsRequest - -class StreamDatapointsReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class ErrorsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: builtins.int - value: sdv.databroker.v1.types_pb2.DatapointError.ValueType - def __init__(self, - *, - key: builtins.int = ..., - value: sdv.databroker.v1.types_pb2.DatapointError.ValueType = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - ERRORS_FIELD_NUMBER: builtins.int - @property - def errors(self) -> google.protobuf.internal.containers.ScalarMap[builtins.int, sdv.databroker.v1.types_pb2.DatapointError.ValueType]: - """If empty, everything went well""" - pass - def __init__(self, - *, - errors: typing.Optional[typing.Mapping[builtins.int, sdv.databroker.v1.types_pb2.DatapointError.ValueType]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["errors",b"errors"]) -> None: ... -global___StreamDatapointsReply = StreamDatapointsReply - -class RegisterDatapointsRequest(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - LIST_FIELD_NUMBER: builtins.int - @property - def list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___RegistrationMetadata]: ... - def __init__(self, - *, - list: typing.Optional[typing.Iterable[global___RegistrationMetadata]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["list",b"list"]) -> None: ... -global___RegisterDatapointsRequest = RegisterDatapointsRequest - -class RegistrationMetadata(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - NAME_FIELD_NUMBER: builtins.int - DATA_TYPE_FIELD_NUMBER: builtins.int - DESCRIPTION_FIELD_NUMBER: builtins.int - CHANGE_TYPE_FIELD_NUMBER: builtins.int - name: typing.Text - """Name of the data point - (e.g. "Vehicle.Cabin.Seat.Row1.Pos1.Position" or "Vehicle.Speed") - """ - - data_type: sdv.databroker.v1.types_pb2.DataType.ValueType - description: typing.Text - change_type: sdv.databroker.v1.types_pb2.ChangeType.ValueType - def __init__(self, - *, - name: typing.Text = ..., - data_type: sdv.databroker.v1.types_pb2.DataType.ValueType = ..., - description: typing.Text = ..., - change_type: sdv.databroker.v1.types_pb2.ChangeType.ValueType = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["change_type",b"change_type","data_type",b"data_type","description",b"description","name",b"name"]) -> None: ... -global___RegistrationMetadata = RegistrationMetadata - -class RegisterDatapointsReply(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class ResultsEntry(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - KEY_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - key: typing.Text - value: builtins.int - def __init__(self, - *, - key: typing.Text = ..., - value: builtins.int = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... - - RESULTS_FIELD_NUMBER: builtins.int - @property - def results(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, builtins.int]: - """Maps each data point name passed in RegisterDatapointsRequest to a data point id""" - pass - def __init__(self, - *, - results: typing.Optional[typing.Mapping[typing.Text, builtins.int]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["results",b"results"]) -> None: ... -global___RegisterDatapointsReply = RegisterDatapointsReply diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2_grpc.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2_grpc.py deleted file mode 100644 index cb73b05a1..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/collector_pb2_grpc.py +++ /dev/null @@ -1,166 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -from gen_proto.sdv.databroker.v1 import collector_pb2 as sdv_dot_databroker_dot_v1_dot_collector__pb2 - - -class CollectorStub(object): - """Missing associated documentation comment in .proto file.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.RegisterDatapoints = channel.unary_unary( - '/sdv.databroker.v1.Collector/RegisterDatapoints', - request_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsReply.FromString, - ) - self.UpdateDatapoints = channel.unary_unary( - '/sdv.databroker.v1.Collector/UpdateDatapoints', - request_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsReply.FromString, - ) - self.StreamDatapoints = channel.stream_stream( - '/sdv.databroker.v1.Collector/StreamDatapoints', - request_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsRequest.SerializeToString, - response_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsReply.FromString, - ) - - -class CollectorServicer(object): - """Missing associated documentation comment in .proto file.""" - - def RegisterDatapoints(self, request, context): - """Register new datapoint (metadata) - - If the registration of at least one of the passed data point fails, the overall registration - is rejected and the gRPC status code ABORTED is returned (to indicate the "aborted" registration). - The details, which data point(s) caused the failure and the reason, is passed in back in human- - readable form in the status message. Possible failure resaons are: - * PERMISSION_DENIED - Not allowed to register this name - * ALREADY_REGISTERED - The data point is already registered by some other feeder - * RE_REGISTRATION_MISMATCH - Already registered by this feeder but with differing metadata - * INVALID_NAME - The passed name of the datapoint has an invalid structure - * INVALID_VALUE_TYPE - The passed ValueType is not supported - * INVALID_CHANGE_TYPE - The passed ChangeType is not supported - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def UpdateDatapoints(self, request, context): - """Provide a set of updated datapoint values to the broker. - This is the unary equivalent of `StreamDatapoints` below and is better suited for cases - where the frequency of updates is rather low. - - NOTE: The values provided in a single request are handled as a single update in the - data broker. This ensures that any clients requesting (or subscribing to) a set of - datapoints will get a consistent update, i.e. that either all values are updated or - none are. - - Returns: any errors encountered updating the datapoints - - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def StreamDatapoints(self, request_iterator, context): - """Provide a stream with updated datapoint values to the broker. - This is the streaming equivalent of `UpdateDatapoints` above and is better suited for - cases where the frequency of updates is high. - - NOTE: The values provided in a single request are handled as a single update in the - data broker. This ensures that any clients requesting (or subscribing to) a set of - datapoints will get a consistent update, i.e. that either all values are updated or - none are. - - Returns: any errors encountered updating the datapoints - - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_CollectorServicer_to_server(servicer, server): - rpc_method_handlers = { - 'RegisterDatapoints': grpc.unary_unary_rpc_method_handler( - servicer.RegisterDatapoints, - request_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsReply.SerializeToString, - ), - 'UpdateDatapoints': grpc.unary_unary_rpc_method_handler( - servicer.UpdateDatapoints, - request_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsReply.SerializeToString, - ), - 'StreamDatapoints': grpc.stream_stream_rpc_method_handler( - servicer.StreamDatapoints, - request_deserializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsRequest.FromString, - response_serializer=sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsReply.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'sdv.databroker.v1.Collector', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) - - - # This class is part of an EXPERIMENTAL API. -class Collector(object): - """Missing associated documentation comment in .proto file.""" - - @staticmethod - def RegisterDatapoints(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/sdv.databroker.v1.Collector/RegisterDatapoints', - sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_collector__pb2.RegisterDatapointsReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def UpdateDatapoints(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/sdv.databroker.v1.Collector/UpdateDatapoints', - sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_collector__pb2.UpdateDatapointsReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def StreamDatapoints(request_iterator, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.stream_stream(request_iterator, target, '/sdv.databroker.v1.Collector/StreamDatapoints', - sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsRequest.SerializeToString, - sdv_dot_databroker_dot_v1_dot_collector__pb2.StreamDatapointsReply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.py deleted file mode 100644 index 7cf9bc4f7..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: sdv/databroker/v1/types.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dsdv/databroker/v1/types.proto\x12\x11sdv.databroker.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1d\n\x0bStringArray\x12\x0e\n\x06values\x18\x01 \x03(\t\"\x1b\n\tBoolArray\x12\x0e\n\x06values\x18\x01 \x03(\x08\"\x1c\n\nInt32Array\x12\x0e\n\x06values\x18\x01 \x03(\x11\"\x1c\n\nInt64Array\x12\x0e\n\x06values\x18\x01 \x03(\x12\"\x1d\n\x0bUint32Array\x12\x0e\n\x06values\x18\x01 \x03(\r\"\x1d\n\x0bUint64Array\x12\x0e\n\x06values\x18\x01 \x03(\x04\"\x1c\n\nFloatArray\x12\x0e\n\x06values\x18\x01 \x03(\x02\"\x1d\n\x0b\x44oubleArray\x12\x0e\n\x06values\x18\x01 \x03(\x01\"\xe2\x06\n\tDatapoint\x12-\n\ttimestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12=\n\rfailure_value\x18\n \x01(\x0e\x32$.sdv.databroker.v1.Datapoint.FailureH\x00\x12\x16\n\x0cstring_value\x18\x0b \x01(\tH\x00\x12\x14\n\nbool_value\x18\x0c \x01(\x08H\x00\x12\x15\n\x0bint32_value\x18\r \x01(\x11H\x00\x12\x15\n\x0bint64_value\x18\x0e \x01(\x12H\x00\x12\x16\n\x0cuint32_value\x18\x0f \x01(\rH\x00\x12\x16\n\x0cuint64_value\x18\x10 \x01(\x04H\x00\x12\x15\n\x0b\x66loat_value\x18\x11 \x01(\x02H\x00\x12\x16\n\x0c\x64ouble_value\x18\x12 \x01(\x01H\x00\x12\x36\n\x0cstring_array\x18\x15 \x01(\x0b\x32\x1e.sdv.databroker.v1.StringArrayH\x00\x12\x32\n\nbool_array\x18\x16 \x01(\x0b\x32\x1c.sdv.databroker.v1.BoolArrayH\x00\x12\x34\n\x0bint32_array\x18\x17 \x01(\x0b\x32\x1d.sdv.databroker.v1.Int32ArrayH\x00\x12\x34\n\x0bint64_array\x18\x18 \x01(\x0b\x32\x1d.sdv.databroker.v1.Int64ArrayH\x00\x12\x36\n\x0cuint32_array\x18\x19 \x01(\x0b\x32\x1e.sdv.databroker.v1.Uint32ArrayH\x00\x12\x36\n\x0cuint64_array\x18\x1a \x01(\x0b\x32\x1e.sdv.databroker.v1.Uint64ArrayH\x00\x12\x34\n\x0b\x66loat_array\x18\x1b \x01(\x0b\x32\x1d.sdv.databroker.v1.FloatArrayH\x00\x12\x36\n\x0c\x64ouble_array\x18\x1c \x01(\x0b\x32\x1e.sdv.databroker.v1.DoubleArrayH\x00\"m\n\x07\x46\x61ilure\x12\x11\n\rINVALID_VALUE\x10\x00\x12\x11\n\rNOT_AVAILABLE\x10\x01\x12\x15\n\x11UNKNOWN_DATAPOINT\x10\x02\x12\x11\n\rACCESS_DENIED\x10\x03\x12\x12\n\x0eINTERNAL_ERROR\x10\x04\x42\x07\n\x05value\"\x9d\x01\n\x08Metadata\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x04 \x01(\t\x12.\n\tdata_type\x18\x05 \x01(\x0e\x32\x1b.sdv.databroker.v1.DataType\x12\x32\n\x0b\x63hange_type\x18\x06 \x01(\x0e\x32\x1d.sdv.databroker.v1.ChangeType\x12\x13\n\x0b\x64\x65scription\x18\x07 \x01(\t*\x84\x03\n\x08\x44\x61taType\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x12\x08\n\x04INT8\x10\x02\x12\t\n\x05INT16\x10\x03\x12\t\n\x05INT32\x10\x04\x12\t\n\x05INT64\x10\x05\x12\t\n\x05UINT8\x10\x06\x12\n\n\x06UINT16\x10\x07\x12\n\n\x06UINT32\x10\x08\x12\n\n\x06UINT64\x10\t\x12\t\n\x05\x46LOAT\x10\n\x12\n\n\x06\x44OUBLE\x10\x0b\x12\r\n\tTIMESTAMP\x10\x0c\x12\x10\n\x0cSTRING_ARRAY\x10\x14\x12\x0e\n\nBOOL_ARRAY\x10\x15\x12\x0e\n\nINT8_ARRAY\x10\x16\x12\x0f\n\x0bINT16_ARRAY\x10\x17\x12\x0f\n\x0bINT32_ARRAY\x10\x18\x12\x0f\n\x0bINT64_ARRAY\x10\x19\x12\x0f\n\x0bUINT8_ARRAY\x10\x1a\x12\x10\n\x0cUINT16_ARRAY\x10\x1b\x12\x10\n\x0cUINT32_ARRAY\x10\x1c\x12\x10\n\x0cUINT64_ARRAY\x10\x1d\x12\x0f\n\x0b\x46LOAT_ARRAY\x10\x1e\x12\x10\n\x0c\x44OUBLE_ARRAY\x10\x1f\x12\x13\n\x0fTIMESTAMP_ARRAY\x10 *s\n\x0e\x44\x61tapointError\x12\x15\n\x11UNKNOWN_DATAPOINT\x10\x00\x12\x10\n\x0cINVALID_TYPE\x10\x01\x12\x11\n\rACCESS_DENIED\x10\x02\x12\x12\n\x0eINTERNAL_ERROR\x10\x03\x12\x11\n\rOUT_OF_BOUNDS\x10\x04*7\n\nChangeType\x12\n\n\x06STATIC\x10\x00\x12\r\n\tON_CHANGE\x10\x01\x12\x0e\n\nCONTINUOUS\x10\x02\x62\x06proto3') - -_DATATYPE = DESCRIPTOR.enum_types_by_name['DataType'] -DataType = enum_type_wrapper.EnumTypeWrapper(_DATATYPE) -_DATAPOINTERROR = DESCRIPTOR.enum_types_by_name['DatapointError'] -DatapointError = enum_type_wrapper.EnumTypeWrapper(_DATAPOINTERROR) -_CHANGETYPE = DESCRIPTOR.enum_types_by_name['ChangeType'] -ChangeType = enum_type_wrapper.EnumTypeWrapper(_CHANGETYPE) -STRING = 0 -BOOL = 1 -INT8 = 2 -INT16 = 3 -INT32 = 4 -INT64 = 5 -UINT8 = 6 -UINT16 = 7 -UINT32 = 8 -UINT64 = 9 -FLOAT = 10 -DOUBLE = 11 -TIMESTAMP = 12 -STRING_ARRAY = 20 -BOOL_ARRAY = 21 -INT8_ARRAY = 22 -INT16_ARRAY = 23 -INT32_ARRAY = 24 -INT64_ARRAY = 25 -UINT8_ARRAY = 26 -UINT16_ARRAY = 27 -UINT32_ARRAY = 28 -UINT64_ARRAY = 29 -FLOAT_ARRAY = 30 -DOUBLE_ARRAY = 31 -TIMESTAMP_ARRAY = 32 -UNKNOWN_DATAPOINT = 0 -INVALID_TYPE = 1 -ACCESS_DENIED = 2 -INTERNAL_ERROR = 3 -OUT_OF_BOUNDS = 4 -STATIC = 0 -ON_CHANGE = 1 -CONTINUOUS = 2 - - -_STRINGARRAY = DESCRIPTOR.message_types_by_name['StringArray'] -_BOOLARRAY = DESCRIPTOR.message_types_by_name['BoolArray'] -_INT32ARRAY = DESCRIPTOR.message_types_by_name['Int32Array'] -_INT64ARRAY = DESCRIPTOR.message_types_by_name['Int64Array'] -_UINT32ARRAY = DESCRIPTOR.message_types_by_name['Uint32Array'] -_UINT64ARRAY = DESCRIPTOR.message_types_by_name['Uint64Array'] -_FLOATARRAY = DESCRIPTOR.message_types_by_name['FloatArray'] -_DOUBLEARRAY = DESCRIPTOR.message_types_by_name['DoubleArray'] -_DATAPOINT = DESCRIPTOR.message_types_by_name['Datapoint'] -_METADATA = DESCRIPTOR.message_types_by_name['Metadata'] -_DATAPOINT_FAILURE = _DATAPOINT.enum_types_by_name['Failure'] -StringArray = _reflection.GeneratedProtocolMessageType('StringArray', (_message.Message,), { - 'DESCRIPTOR' : _STRINGARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.StringArray) - }) -_sym_db.RegisterMessage(StringArray) - -BoolArray = _reflection.GeneratedProtocolMessageType('BoolArray', (_message.Message,), { - 'DESCRIPTOR' : _BOOLARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.BoolArray) - }) -_sym_db.RegisterMessage(BoolArray) - -Int32Array = _reflection.GeneratedProtocolMessageType('Int32Array', (_message.Message,), { - 'DESCRIPTOR' : _INT32ARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Int32Array) - }) -_sym_db.RegisterMessage(Int32Array) - -Int64Array = _reflection.GeneratedProtocolMessageType('Int64Array', (_message.Message,), { - 'DESCRIPTOR' : _INT64ARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Int64Array) - }) -_sym_db.RegisterMessage(Int64Array) - -Uint32Array = _reflection.GeneratedProtocolMessageType('Uint32Array', (_message.Message,), { - 'DESCRIPTOR' : _UINT32ARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Uint32Array) - }) -_sym_db.RegisterMessage(Uint32Array) - -Uint64Array = _reflection.GeneratedProtocolMessageType('Uint64Array', (_message.Message,), { - 'DESCRIPTOR' : _UINT64ARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Uint64Array) - }) -_sym_db.RegisterMessage(Uint64Array) - -FloatArray = _reflection.GeneratedProtocolMessageType('FloatArray', (_message.Message,), { - 'DESCRIPTOR' : _FLOATARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.FloatArray) - }) -_sym_db.RegisterMessage(FloatArray) - -DoubleArray = _reflection.GeneratedProtocolMessageType('DoubleArray', (_message.Message,), { - 'DESCRIPTOR' : _DOUBLEARRAY, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.DoubleArray) - }) -_sym_db.RegisterMessage(DoubleArray) - -Datapoint = _reflection.GeneratedProtocolMessageType('Datapoint', (_message.Message,), { - 'DESCRIPTOR' : _DATAPOINT, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Datapoint) - }) -_sym_db.RegisterMessage(Datapoint) - -Metadata = _reflection.GeneratedProtocolMessageType('Metadata', (_message.Message,), { - 'DESCRIPTOR' : _METADATA, - '__module__' : 'sdv.databroker.v1.types_pb2' - # @@protoc_insertion_point(class_scope:sdv.databroker.v1.Metadata) - }) -_sym_db.RegisterMessage(Metadata) - -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _DATATYPE._serialized_start=1358 - _DATATYPE._serialized_end=1746 - _DATAPOINTERROR._serialized_start=1748 - _DATAPOINTERROR._serialized_end=1863 - _CHANGETYPE._serialized_start=1865 - _CHANGETYPE._serialized_end=1920 - _STRINGARRAY._serialized_start=85 - _STRINGARRAY._serialized_end=114 - _BOOLARRAY._serialized_start=116 - _BOOLARRAY._serialized_end=143 - _INT32ARRAY._serialized_start=145 - _INT32ARRAY._serialized_end=173 - _INT64ARRAY._serialized_start=175 - _INT64ARRAY._serialized_end=203 - _UINT32ARRAY._serialized_start=205 - _UINT32ARRAY._serialized_end=234 - _UINT64ARRAY._serialized_start=236 - _UINT64ARRAY._serialized_end=265 - _FLOATARRAY._serialized_start=267 - _FLOATARRAY._serialized_end=295 - _DOUBLEARRAY._serialized_start=297 - _DOUBLEARRAY._serialized_end=326 - _DATAPOINT._serialized_start=329 - _DATAPOINT._serialized_end=1195 - _DATAPOINT_FAILURE._serialized_start=1077 - _DATAPOINT_FAILURE._serialized_end=1186 - _METADATA._serialized_start=1198 - _METADATA._serialized_end=1355 -# @@protoc_insertion_point(module_scope) diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.pyi b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.pyi deleted file mode 100644 index 735a9207b..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2.pyi +++ /dev/null @@ -1,375 +0,0 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import google.protobuf.timestamp_pb2 -import typing -import typing_extensions - -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _DataType: - ValueType = typing.NewType('ValueType', builtins.int) - V: typing_extensions.TypeAlias = ValueType -class _DataTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DataType.ValueType], builtins.type): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - STRING: _DataType.ValueType # 0 - BOOL: _DataType.ValueType # 1 - INT8: _DataType.ValueType # 2 - INT16: _DataType.ValueType # 3 - INT32: _DataType.ValueType # 4 - INT64: _DataType.ValueType # 5 - UINT8: _DataType.ValueType # 6 - UINT16: _DataType.ValueType # 7 - UINT32: _DataType.ValueType # 8 - UINT64: _DataType.ValueType # 9 - FLOAT: _DataType.ValueType # 10 - DOUBLE: _DataType.ValueType # 11 - TIMESTAMP: _DataType.ValueType # 12 - STRING_ARRAY: _DataType.ValueType # 20 - BOOL_ARRAY: _DataType.ValueType # 21 - INT8_ARRAY: _DataType.ValueType # 22 - INT16_ARRAY: _DataType.ValueType # 23 - INT32_ARRAY: _DataType.ValueType # 24 - INT64_ARRAY: _DataType.ValueType # 25 - UINT8_ARRAY: _DataType.ValueType # 26 - UINT16_ARRAY: _DataType.ValueType # 27 - UINT32_ARRAY: _DataType.ValueType # 28 - UINT64_ARRAY: _DataType.ValueType # 29 - FLOAT_ARRAY: _DataType.ValueType # 30 - DOUBLE_ARRAY: _DataType.ValueType # 31 - TIMESTAMP_ARRAY: _DataType.ValueType # 32 -class DataType(_DataType, metaclass=_DataTypeEnumTypeWrapper): - """Data type of a signal - - Protobuf doesn't support int8, int16, uint8 or uint16. - These are mapped to sint32 and uint32 respectively. - """ - pass - -STRING: DataType.ValueType # 0 -BOOL: DataType.ValueType # 1 -INT8: DataType.ValueType # 2 -INT16: DataType.ValueType # 3 -INT32: DataType.ValueType # 4 -INT64: DataType.ValueType # 5 -UINT8: DataType.ValueType # 6 -UINT16: DataType.ValueType # 7 -UINT32: DataType.ValueType # 8 -UINT64: DataType.ValueType # 9 -FLOAT: DataType.ValueType # 10 -DOUBLE: DataType.ValueType # 11 -TIMESTAMP: DataType.ValueType # 12 -STRING_ARRAY: DataType.ValueType # 20 -BOOL_ARRAY: DataType.ValueType # 21 -INT8_ARRAY: DataType.ValueType # 22 -INT16_ARRAY: DataType.ValueType # 23 -INT32_ARRAY: DataType.ValueType # 24 -INT64_ARRAY: DataType.ValueType # 25 -UINT8_ARRAY: DataType.ValueType # 26 -UINT16_ARRAY: DataType.ValueType # 27 -UINT32_ARRAY: DataType.ValueType # 28 -UINT64_ARRAY: DataType.ValueType # 29 -FLOAT_ARRAY: DataType.ValueType # 30 -DOUBLE_ARRAY: DataType.ValueType # 31 -TIMESTAMP_ARRAY: DataType.ValueType # 32 -global___DataType = DataType - - -class _DatapointError: - ValueType = typing.NewType('ValueType', builtins.int) - V: typing_extensions.TypeAlias = ValueType -class _DatapointErrorEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DatapointError.ValueType], builtins.type): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - UNKNOWN_DATAPOINT: _DatapointError.ValueType # 0 - INVALID_TYPE: _DatapointError.ValueType # 1 - ACCESS_DENIED: _DatapointError.ValueType # 2 - INTERNAL_ERROR: _DatapointError.ValueType # 3 - OUT_OF_BOUNDS: _DatapointError.ValueType # 4 -class DatapointError(_DatapointError, metaclass=_DatapointErrorEnumTypeWrapper): - pass - -UNKNOWN_DATAPOINT: DatapointError.ValueType # 0 -INVALID_TYPE: DatapointError.ValueType # 1 -ACCESS_DENIED: DatapointError.ValueType # 2 -INTERNAL_ERROR: DatapointError.ValueType # 3 -OUT_OF_BOUNDS: DatapointError.ValueType # 4 -global___DatapointError = DatapointError - - -class _ChangeType: - ValueType = typing.NewType('ValueType', builtins.int) - V: typing_extensions.TypeAlias = ValueType -class _ChangeTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ChangeType.ValueType], builtins.type): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - STATIC: _ChangeType.ValueType # 0 - """Value never changes""" - - ON_CHANGE: _ChangeType.ValueType # 1 - """Updates are provided every time the value changes (i.e.""" - - CONTINUOUS: _ChangeType.ValueType # 2 - """window is open / closed) - Value is updated continuously. Broker needs to tell - """ - -class ChangeType(_ChangeType, metaclass=_ChangeTypeEnumTypeWrapper): - pass - -STATIC: ChangeType.ValueType # 0 -"""Value never changes""" - -ON_CHANGE: ChangeType.ValueType # 1 -"""Updates are provided every time the value changes (i.e.""" - -CONTINUOUS: ChangeType.ValueType # 2 -"""window is open / closed) -Value is updated continuously. Broker needs to tell -""" - -global___ChangeType = ChangeType - - -class StringArray(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[typing.Text]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___StringArray = StringArray - -class BoolArray(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.bool]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.bool]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___BoolArray = BoolArray - -class Int32Array(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.int]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___Int32Array = Int32Array - -class Int64Array(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.int]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___Int64Array = Int64Array - -class Uint32Array(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.int]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___Uint32Array = Uint32Array - -class Uint64Array(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.int]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___Uint64Array = Uint64Array - -class FloatArray(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.float]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.float]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___FloatArray = FloatArray - -class DoubleArray(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - VALUES_FIELD_NUMBER: builtins.int - @property - def values(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.float]: ... - def __init__(self, - *, - values: typing.Optional[typing.Iterable[builtins.float]] = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["values",b"values"]) -> None: ... -global___DoubleArray = DoubleArray - -class Datapoint(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - class _Failure: - ValueType = typing.NewType('ValueType', builtins.int) - V: typing_extensions.TypeAlias = ValueType - class _FailureEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Datapoint._Failure.ValueType], builtins.type): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - INVALID_VALUE: Datapoint._Failure.ValueType # 0 - """The data point is known, but doesn't have a valid value""" - - NOT_AVAILABLE: Datapoint._Failure.ValueType # 1 - """The data point is known, but no value is available""" - - UNKNOWN_DATAPOINT: Datapoint._Failure.ValueType # 2 - """Unknown datapoint""" - - ACCESS_DENIED: Datapoint._Failure.ValueType # 3 - """Access denied""" - - INTERNAL_ERROR: Datapoint._Failure.ValueType # 4 - """Unexpected internal error""" - - class Failure(_Failure, metaclass=_FailureEnumTypeWrapper): - pass - - INVALID_VALUE: Datapoint.Failure.ValueType # 0 - """The data point is known, but doesn't have a valid value""" - - NOT_AVAILABLE: Datapoint.Failure.ValueType # 1 - """The data point is known, but no value is available""" - - UNKNOWN_DATAPOINT: Datapoint.Failure.ValueType # 2 - """Unknown datapoint""" - - ACCESS_DENIED: Datapoint.Failure.ValueType # 3 - """Access denied""" - - INTERNAL_ERROR: Datapoint.Failure.ValueType # 4 - """Unexpected internal error""" - - - TIMESTAMP_FIELD_NUMBER: builtins.int - FAILURE_VALUE_FIELD_NUMBER: builtins.int - STRING_VALUE_FIELD_NUMBER: builtins.int - BOOL_VALUE_FIELD_NUMBER: builtins.int - INT32_VALUE_FIELD_NUMBER: builtins.int - INT64_VALUE_FIELD_NUMBER: builtins.int - UINT32_VALUE_FIELD_NUMBER: builtins.int - UINT64_VALUE_FIELD_NUMBER: builtins.int - FLOAT_VALUE_FIELD_NUMBER: builtins.int - DOUBLE_VALUE_FIELD_NUMBER: builtins.int - STRING_ARRAY_FIELD_NUMBER: builtins.int - BOOL_ARRAY_FIELD_NUMBER: builtins.int - INT32_ARRAY_FIELD_NUMBER: builtins.int - INT64_ARRAY_FIELD_NUMBER: builtins.int - UINT32_ARRAY_FIELD_NUMBER: builtins.int - UINT64_ARRAY_FIELD_NUMBER: builtins.int - FLOAT_ARRAY_FIELD_NUMBER: builtins.int - DOUBLE_ARRAY_FIELD_NUMBER: builtins.int - @property - def timestamp(self) -> google.protobuf.timestamp_pb2.Timestamp: - """Timestamp of the value""" - pass - failure_value: global___Datapoint.Failure.ValueType - string_value: typing.Text - bool_value: builtins.bool - int32_value: builtins.int - int64_value: builtins.int - uint32_value: builtins.int - uint64_value: builtins.int - float_value: builtins.float - double_value: builtins.float - @property - def string_array(self) -> global___StringArray: ... - @property - def bool_array(self) -> global___BoolArray: ... - @property - def int32_array(self) -> global___Int32Array: ... - @property - def int64_array(self) -> global___Int64Array: ... - @property - def uint32_array(self) -> global___Uint32Array: ... - @property - def uint64_array(self) -> global___Uint64Array: ... - @property - def float_array(self) -> global___FloatArray: ... - @property - def double_array(self) -> global___DoubleArray: ... - def __init__(self, - *, - timestamp: typing.Optional[google.protobuf.timestamp_pb2.Timestamp] = ..., - failure_value: global___Datapoint.Failure.ValueType = ..., - string_value: typing.Text = ..., - bool_value: builtins.bool = ..., - int32_value: builtins.int = ..., - int64_value: builtins.int = ..., - uint32_value: builtins.int = ..., - uint64_value: builtins.int = ..., - float_value: builtins.float = ..., - double_value: builtins.float = ..., - string_array: typing.Optional[global___StringArray] = ..., - bool_array: typing.Optional[global___BoolArray] = ..., - int32_array: typing.Optional[global___Int32Array] = ..., - int64_array: typing.Optional[global___Int64Array] = ..., - uint32_array: typing.Optional[global___Uint32Array] = ..., - uint64_array: typing.Optional[global___Uint64Array] = ..., - float_array: typing.Optional[global___FloatArray] = ..., - double_array: typing.Optional[global___DoubleArray] = ..., - ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["bool_array",b"bool_array","bool_value",b"bool_value","double_array",b"double_array","double_value",b"double_value","failure_value",b"failure_value","float_array",b"float_array","float_value",b"float_value","int32_array",b"int32_array","int32_value",b"int32_value","int64_array",b"int64_array","int64_value",b"int64_value","string_array",b"string_array","string_value",b"string_value","timestamp",b"timestamp","uint32_array",b"uint32_array","uint32_value",b"uint32_value","uint64_array",b"uint64_array","uint64_value",b"uint64_value","value",b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["bool_array",b"bool_array","bool_value",b"bool_value","double_array",b"double_array","double_value",b"double_value","failure_value",b"failure_value","float_array",b"float_array","float_value",b"float_value","int32_array",b"int32_array","int32_value",b"int32_value","int64_array",b"int64_array","int64_value",b"int64_value","string_array",b"string_array","string_value",b"string_value","timestamp",b"timestamp","uint32_array",b"uint32_array","uint32_value",b"uint32_value","uint64_array",b"uint64_array","uint64_value",b"uint64_value","value",b"value"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal["value",b"value"]) -> typing.Optional[typing_extensions.Literal["failure_value","string_value","bool_value","int32_value","int64_value","uint32_value","uint64_value","float_value","double_value","string_array","bool_array","int32_array","int64_array","uint32_array","uint64_array","float_array","double_array"]]: ... -global___Datapoint = Datapoint - -class Metadata(google.protobuf.message.Message): - DESCRIPTOR: google.protobuf.descriptor.Descriptor - ID_FIELD_NUMBER: builtins.int - NAME_FIELD_NUMBER: builtins.int - DATA_TYPE_FIELD_NUMBER: builtins.int - CHANGE_TYPE_FIELD_NUMBER: builtins.int - DESCRIPTION_FIELD_NUMBER: builtins.int - id: builtins.int - """Id to be used in "get" and "subscribe" requests. Ids stay valid during - one power cycle, only. - """ - - name: typing.Text - data_type: global___DataType.ValueType - change_type: global___ChangeType.ValueType - """CONTINUOUS or STATIC or ON_CHANGE""" - - description: typing.Text - def __init__(self, - *, - id: builtins.int = ..., - name: typing.Text = ..., - data_type: global___DataType.ValueType = ..., - change_type: global___ChangeType.ValueType = ..., - description: typing.Text = ..., - ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["change_type",b"change_type","data_type",b"data_type","description",b"description","id",b"id","name",b"name"]) -> None: ... -global___Metadata = Metadata diff --git a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2_grpc.py b/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2_grpc.py deleted file mode 100644 index 2daafffeb..000000000 --- a/kuksa_databroker/integration_test/gen_proto/sdv/databroker/v1/types_pb2_grpc.py +++ /dev/null @@ -1,4 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - diff --git a/kuksa_databroker/integration_test/helper.py b/kuksa_databroker/integration_test/helper.py deleted file mode 100644 index fd8f61c03..000000000 --- a/kuksa_databroker/integration_test/helper.py +++ /dev/null @@ -1,403 +0,0 @@ -# /******************************************************************************** -# * Copyright (c) 2022 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -# Disable name checks due to proto generated classes -# pylint: disable=C0103 - -import asyncio -import logging -import os -import signal -import threading -from threading import Thread -from typing import Any, Callable, Dict, List, Mapping, Optional - -import grpc -import pytest -from gen_proto.sdv.databroker.v1.broker_pb2 import ( - GetDatapointsRequest, - GetMetadataRequest, - SubscribeRequest, -) -from gen_proto.sdv.databroker.v1.broker_pb2_grpc import BrokerStub -from gen_proto.sdv.databroker.v1.collector_pb2 import ( - RegisterDatapointsRequest, - RegistrationMetadata, - UpdateDatapointsRequest, -) -from gen_proto.sdv.databroker.v1.collector_pb2_grpc import CollectorStub -from gen_proto.sdv.databroker.v1.types_pb2 import ChangeType, Datapoint, DataType - -logger = logging.getLogger(__name__) - - -class Databroker: - """ - Databroker wraps collector and broker APIs of the databroker. - """ - - @classmethod - async def ConnectedDatabroker(cls, address: str): - self = Databroker(address) - await self.await_connectivity() - return self - - def __init__(self, address: str) -> None: - - self._address = address - - logger.info("Databroker connecting to {}".format(self._address)) - # WARNING: always await grpc response! - self._channel = grpc.aio.insecure_channel(self._address) # type: ignore - - self._collector_stub = CollectorStub(self._channel) - self._broker_stub = BrokerStub(self._channel) - self._ids: Dict[str, int] = None # type: ignore - self._metadata = None - - async def close(self) -> None: - """Closes runtime gRPC channel.""" - if self._channel: - await self._channel.close() - - def __enter__(self) -> "Databroker": - return self - - def __exit__(self, exc_type, exc_value, traceback) -> None: - asyncio.run_coroutine_threadsafe(self.close(), asyncio.get_event_loop()) - - async def __register_datapoints(self, datapoints: list): - response = await self._collector_stub.RegisterDatapoints( - RegisterDatapointsRequest(list=datapoints) - ) - return response - - async def __update_datapoints(self, datapoints: Mapping[int, Datapoint]): - response = await self._collector_stub.UpdateDatapoints( - UpdateDatapointsRequest(datapoints=datapoints) - ) - return response - - async def __get_datapoints(self, datapoints: list): - response = await self._broker_stub.GetDatapoints( - GetDatapointsRequest(datapoints=datapoints) - ) - return response - - async def await_connectivity(self): - # We need to "manually" wait in a loop, as wait_for_state_change can not wait for a - # specific target state - tries = 0 - while tries < 10: - state = self._channel.get_state(try_to_connect=True) - logger.info("GRPC State is %s", state) - if state == grpc.ChannelConnectivity.READY: - break - logger.info("Try %i: Waiting for GRPC connection to become READY...", tries) - tries = tries + 1 - try: - await asyncio.wait_for(self._channel.wait_for_state_change(state), timeout=2) - except asyncio.exceptions.TimeoutError: - # We need to catch this, and will wait again until tries are used up - pass - - async def get_metadata(self, names=[]): - """Requests metadata from databroker, allows for optional list of names - - Args: - names (list, optional): List of names to get. Defaults to []. - - Returns: - _type_: list, can be converted to json using parse_metadata() - """ - response = await self._broker_stub.GetMetadata( - GetMetadataRequest(names=names) - ) - return response.list - - def metadata_to_json(self, metadata) -> list: - """Parses metadata.list to json format - - Args: - metadata (_type_): MetaDataReply.list - - Returns: - list: Json objects - """ - return [ - { - "id": m.id, - "name": m.name, - "data_type": m.data_type, - "description": m.description, - } - for m in metadata - ] - - def datapoint_to_dict(self, name: str, dp: Datapoint) -> dict: - """Convert Datapoint object to dictionary - - Args: - name (str): Datapoint Name - dp (Datapoint): Datapoint - - Returns: - dict: with keys "name", "ts", "value", "type" - """ - value_type = dp.WhichOneof("value") - if value_type: - # try to get directly dp.${which_one} attribute - value = getattr(dp, value_type) - ts = ( - dp.timestamp.seconds + int(dp.timestamp.nanos / 10**6) / 1000 - ) # round to msec - result = {"name": name, "ts": ts, "value": value, "type": value_type} - return result - - async def get_datapoints(self, datapoints=None): - if datapoints is None: - await self.__initialize_metadata() - datapoints = self._ids.keys() - - response = await self.__get_datapoints(datapoints=datapoints) - # map datapoints = 1; - return response - - async def __initialize_metadata(self, names=[]) -> None: - if self._ids is None: - self._ids = {} - response = await self._broker_stub.GetMetadata([]) - self._metadata = response.list - - for item in response.list: - self._ids[item.name] = item.id - - async def __get_or_create_datapoint_id_by_name( - self, name: str, data_type: DataType - ): - await self.__initialize_metadata() - - key_list = self._ids.keys() - if name not in key_list: - response = await self.register_datapoint(name, data_type) - datapoint_id = int(response) - self._ids[name] = datapoint_id - - return self._ids[name] - - async def register_datapoint(self, name: str, data_type: DataType) -> int: - await self.__initialize_metadata() - - registration_metadata = RegistrationMetadata() - registration_metadata.name = name - registration_metadata.data_type = data_type - registration_metadata.description = "" - registration_metadata.change_type = ChangeType.CONTINUOUS - - response = await self.__register_datapoints(datapoints=[registration_metadata]) - metadata_id = int(response.results[name]) - self._ids[name] = metadata_id - return metadata_id - - async def set_int32_datapoint(self, name: str, value: int): - datapoint = Datapoint() - datapoint.int32_value = value - datapoint_id = await self.__get_or_create_datapoint_id_by_name( - name, DataType.INT32 # type: ignore - ) - return await self.__update_datapoints({datapoint_id: datapoint}) - - async def set_uint32_datapoint(self, name: str, value: int): - datapoint = Datapoint() - datapoint.uint32_value = value - datapoint_id = await self.__get_or_create_datapoint_id_by_name( - name, DataType.UINT32 # type: ignore - ) - return await self.__update_datapoints({datapoint_id: datapoint}) - - async def set_float_datapoint(self, name: str, value: float): - datapoint = Datapoint() - datapoint.float_value = value - datapoint_id = await self.__get_or_create_datapoint_id_by_name( - name, DataType.FLOAT # type: ignore - ) - return await self.__update_datapoints({datapoint_id: datapoint}) - - def __get_grpc_error(self, err: grpc.RpcError) -> str: - status_code = err.code() - return "grpcError[Status:{} {}, details:'{}']".format( - status_code.name, status_code.value, err.details() - ) - - async def subscribe_datapoints( - self, - query: str, - sub_callback: Callable[[str, Datapoint], None], - timeout: Optional[int] = None, - ) -> None: - try: - request = SubscribeRequest(query=query) - logger.info("broker.Subscribe('{}')".format(query)) - response = self._broker_stub.Subscribe( - request, timeout=timeout - ) - # NOTE: - # 'async for' before iteration is crucial here with aio.channel! - async for subscribe_reply in response: - logger.debug("Streaming SubscribeReply %s", subscribe_reply) - """ from broker.proto: - message SubscribeReply { - // Contains the fields specified by the query. - // If a requested data point value is not available, the corresponding - // Datapoint will have it's respective failure value set. - map fields = 1; - }""" - if not hasattr(subscribe_reply, "fields"): - raise Exception("Missing 'fields' in {}".format(subscribe_reply)) - - logger.debug("SubscribeReply.{}".format(subscribe_reply.fields)) - for name in subscribe_reply.fields: - dp = subscribe_reply.fields[name] - try: - logger.debug("Calling sub_callback({}, dp:{})".format(name, dp)) - sub_callback(name, dp) - except Exception: - logging.exception("sub_callback() error", exc_info=True) - pass - logger.debug("Streaming SubscribeReply done...") - - except grpc.RpcError as e: - if ( - e.code() == grpc.StatusCode.DEADLINE_EXCEEDED - ): # expected code if we used timeout, just stop subscription - logger.debug("Exitting after timeout: {}".format(timeout)) - else: - logging.error( - "broker.Subscribe({}) failed!\n --> {}".format( - query, self.__get_grpc_error(e) - ) - ) - raise e - except Exception: - logging.exception("broker.Subscribe() error", exc_info=True) - - -def __on_subscribe_event(name: str, dp: Datapoint) -> None: - value_type = dp.WhichOneof("value") - if value_type: - # try to get directly dp.${which_one} attribute - value = getattr(dp, value_type) - ts = ( - dp.timestamp.seconds + int(dp.timestamp.nanos / 10**6) / 1000 - ) # round to msec - - print( - "#SUB# name:{}, value:{}, value_type:{}, ts:{}".format( - name, value, value_type, ts - ), - flush=True, - ) - - -class SubscribeRunner: - - """ - Helper for gathering subscription events in a dedicated thread, - running for specified timeout - """ - - def __init__(self, databroker_address: str, query: str, timeout: int) -> None: - self.databroker_address = databroker_address - self.query = query - self.timeout = timeout - self.thread: Optional[Thread] = None - self.helper: Databroker - self.events: Dict[str, Any] = {} - - def start(self) -> None: - if self.thread is not None: - raise RuntimeWarning("Thread %s already started!", self.thread.name) - self.thread = Thread( - target=self.__subscibe_thread_proc, - name="SubscribeRunner({})".format(self.query), - ) - self.thread.setDaemon(True) - self.thread.start() - - def get_events(self): - self.close() - return self.events - - def get_dp_values(self, dp_name: str) -> List[Datapoint]: - return [dp["value"] for dp in self.events[dp_name]] - - def find_dp_value(self, dp_name: str, dp_value: Any) -> Datapoint: - if dp_name not in self.events: - return None - for dp in self.events[dp_name]: - val = dp["value"] - if val == dp_value: - return dp - elif isinstance(val, float) and dp_value == pytest.approx(val, 0.1): - # allow 'fuzzy' float matching - return dp - return None - - def close(self) -> None: - if self.thread is not None: - logger.debug("Waiting for thread: %s", threading.current_thread().name) - self.thread.join() - self.thread = None - - async def __async_handler(self) -> Dict[str, Any]: - def inner_callback(name: str, dp: Datapoint): - """inner function for collecting subscription events""" - dd = self.helper.datapoint_to_dict(name, dp) - if name not in self.events: - self.events[name] = [] - self.events[name].append(dd) - - # start client requests in different thread as subscribe_datapoints will block... - logger.info("# subscribing('{}', timeout={})".format(self.query, self.timeout)) - try: - await self.helper.subscribe_datapoints( - self.query, timeout=self.timeout, sub_callback=inner_callback - ) - return self.events - except Exception as ex: - logger.warning("Subscribe(%s) failed", self.query, exc_info=True) - raise ex - - def __subscibe_thread_proc(self) -> None: - # create dedicated event loop and instantiate Databroker in it - logger.info("Thread %s started.", threading.current_thread().name) - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - logger.debug("Waiting %d sec for subscription [%s]", self.timeout, self.query) - self.helper = Databroker(self.databroker_address) - loop.run_until_complete(self.__async_handler()) - - logger.debug( - "Closing helper %d sec for subscription [%s]", self.timeout, self.query - ) - loop.run_until_complete(self.helper.close()) - - loop.close() - logger.info("Thread %s finished.", threading.current_thread().name) - - -if __name__ == "__main__": - LOOP = asyncio.get_event_loop() - LOOP.add_signal_handler(signal.SIGTERM, LOOP.stop) - LOOP.run_until_complete(main()) - LOOP.close() diff --git a/kuksa_databroker/integration_test/requirements-dev.txt b/kuksa_databroker/integration_test/requirements-dev.txt deleted file mode 100644 index 1d340949c..000000000 --- a/kuksa_databroker/integration_test/requirements-dev.txt +++ /dev/null @@ -1,3 +0,0 @@ -grpcio-tools -mypy -mypy-protobuf \ No newline at end of file diff --git a/kuksa_databroker/integration_test/requirements.txt b/kuksa_databroker/integration_test/requirements.txt deleted file mode 100644 index 010d866e5..000000000 --- a/kuksa_databroker/integration_test/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -asyncio -grpcio -protobuf -pytest -pytest-ordering -pytest-asyncio diff --git a/kuksa_databroker/integration_test/run.sh b/kuksa_databroker/integration_test/run.sh deleted file mode 100755 index 84d19eccd..000000000 --- a/kuksa_databroker/integration_test/run.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -#******************************************************************************** -# Copyright (c) 2022 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Setup -python3 -m venv .venv -source .venv/bin/activate -pip install -r "${SCRIPT_DIR}"/requirements.txt - - -DATABROKER_IMAGE=${DATABROKER_IMAGE:-"ghcr.io/eclipse/kuksa.val/databroker:0.4.0"} -DATABROKER_ADDRESS=${DATABROKER_ADDRESS:-"127.0.0.1:55555"} -CONTAINER_PLATFORM=${CONTAINER_PLATFORM:-"linux/amd64"} - -VSS_DATA_DIR="$SCRIPT_DIR/../../data" - -echo "Starting databroker container (\"${DATABROKER_IMAGE}\") in insecure mode, requesting platform (\"${CONTAINER_PLATFORM}\")" -RUNNING_IMAGE=$( - docker run -d -v ${VSS_DATA_DIR}:/data -p 55555:55555 --rm --platform ${CONTAINER_PLATFORM} ${DATABROKER_IMAGE} --metadata data/vss-core/vss_release_4.0.json --insecure -) - -python3 -m pytest -v "${SCRIPT_DIR}/test_databroker.py" - -RESULT=$? - -echo "Stopping databroker container" - -docker stop ${RUNNING_IMAGE} - -exit $RESULT diff --git a/kuksa_databroker/integration_test/test_databroker.py b/kuksa_databroker/integration_test/test_databroker.py deleted file mode 100644 index ce1efb0fe..000000000 --- a/kuksa_databroker/integration_test/test_databroker.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python3 -# /******************************************************************************** -# * Copyright (c) 2022 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ - -import json -import logging -import os - -import asyncio -import pytest - -from gen_proto.sdv.databroker.v1.types_pb2 import Datapoint -from helper import Databroker - -logger = logging.getLogger(__name__) -logger.setLevel(os.getenv("LOG_LEVEL", "WARN")) - -DATABROKER_ADDRESS = os.environ.get("DATABROKER_ADDRESS", "127.0.0.1:55555") - - -@pytest.fixture -async def setup_helper() -> Databroker: - logger.info("Using DATABROKER_ADDRESS={}".format(DATABROKER_ADDRESS)) - helper = await Databroker.ConnectedDatabroker(DATABROKER_ADDRESS) - return helper - - -@pytest.mark.asyncio -async def test_databroker_connection() -> None: - logger.info("Connecting to VehicleDataBroker {}".format(DATABROKER_ADDRESS)) - helper = await Databroker.ConnectedDatabroker(DATABROKER_ADDRESS) - await helper.get_metadata() - logger.info("Databroker._address = {}".format(helper._address)) - await helper.close() - - -@pytest.mark.asyncio -async def test_feeder_metadata_registered(setup_helper: Databroker) -> None: - helper = await setup_helper - feeder_names = [ - "Vehicle.OBD.Speed", - "Vehicle.Powertrain.Transmission.CurrentGear", - "Vehicle.Chassis.ParkingBrake.IsEngaged", - "Vehicle.OBD.EngineLoad", - ] - - meta = await helper.get_metadata(feeder_names) - logger.debug( - "# get_metadata({}) -> \n{}".format( - feeder_names, str(meta).replace("\n", " ") - ) - ) - - assert len(meta) > 0, "databroker metadata is empty" # nosec B101 - assert len(meta) == len( # nosec B101 - feeder_names - ), "Filtered meta with unexpected size: {}".format(meta) - meta_list = helper.metadata_to_json(meta) - logger.debug("get_metadata() --> \n{}".format(json.dumps(meta_list, indent=2))) - - meta_names = [d["name"] for d in meta_list] - - for name in feeder_names: - assert name in meta_names, "{} not registered!".format(name) # nosec B101 - - name_reg = meta_list[meta_names.index(name)] - - assert len(name_reg) == 4 and name_reg["name"] == name # nosec B101 - logger.info("[feeder] Found metadata: {}".format(name_reg)) - # TODO: check for expected types? - # assert ( # nosec B101 - # name_reg["data_type"] == DataType.UINT32 - # ), "{} datatype is {}".format(name, name_reg["data_type"]) - - await helper.close() - - -@pytest.mark.asyncio -async def test_events(setup_helper: Databroker) -> None: - helper: Databroker = await setup_helper - - timeout = 3 - datapoint_speed = "Vehicle.OBD.Speed" # float - datapoint_engine_load = "Vehicle.OBD.EngineLoad" # float - alias_speed = "speed" - alias_load = "load" - - query = "SELECT {} as {}, {} as {}".format(datapoint_speed, alias_speed, datapoint_engine_load, alias_load) - - events = [] - # inner function for collecting subscription events - - def inner_callback(name: str, dp: Datapoint): - dd = helper.datapoint_to_dict(name, dp) - events.append(dd) - - logger.info("# subscribing('{}', timeout={})".format(query, timeout)) - - subscription = asyncio.create_task( - helper.subscribe_datapoints(query, timeout=timeout, sub_callback=inner_callback) - ) - - set_name1 = asyncio.create_task( - helper.set_float_datapoint(datapoint_speed, 40.0) - ) - set_name2 = asyncio.create_task( - helper.set_float_datapoint(datapoint_engine_load, 10.0) - ) - - await set_name1 - await set_name2 - await subscription - - logger.debug("Received events:{}".format(events)) - - assert len(events) > 0, "No events from feeder for {} sec.".format( # nosec B101 - timeout - ) - - # list of received names - event_names = set([e["name"] for e in events]) - # list of received values - alias_values1 = set([e["value"] for e in events if e["name"] == alias_speed]) - alias_values2 = set([e["value"] for e in events if e["name"] == alias_load]) - - logger.debug(" --> names : {}".format(event_names)) - # event_values = [e['value'] for e in events] - # logger.debug(" --> values : {}".format(event_values)) - # logger.debug(" --> <{}> : {}".format(name, event_values_name)) - - assert set([alias_speed, alias_load]) == set( # nosec B101 - event_names - ), "Unexpected event aliases received: {}".format(event_names) - - # don't be too harsh, big capture.log file may have gaps in some of the events - assert ( # nosec B101 - len(alias_values1) > 1 or len(alias_values2) > 1 - ), "{} values not changing: {}. Is feeder running?".format(alias_speed, alias_values1) - - await helper.close() - - -if __name__ == "__main__": - pytest.main(["-vvs", "--log-cli-level=INFO", os.path.abspath(__file__)]) diff --git a/kuksa_databroker/integration_test/update-proto.sh b/kuksa_databroker/integration_test/update-proto.sh deleted file mode 100755 index c0a5248b2..000000000 --- a/kuksa_databroker/integration_test/update-proto.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -# /******************************************************************************** -# * Copyright (c) 2022 Contributors to the Eclipse Foundation -# * -# * See the NOTICE file(s) distributed with this work for additional -# * information regarding copyright ownership. -# * -# * This program and the accompanying materials are made available under the -# * terms of the Apache License 2.0 which is available at -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * SPDX-License-Identifier: Apache-2.0 -# ********************************************************************************/ -# shellcheck disable=SC2086 - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$SCRIPT_DIR" || exit 1 - -GEN_DIR="${SCRIPT_DIR}/gen_proto" - -[ -d "$GEN_DIR" ] || mkdir -p "$GEN_DIR" - -DATABROKER_PROTO="${SCRIPT_DIR}/../proto" - -if [ ! -d "$DATABROKER_PROTO" ]; then - echo "Warning! Can't find DataBroker proto dir in: $DATABROKER_PROTO" - exit 1 -fi - -set -xe -PROTO_FILES=$(find "$DATABROKER_PROTO" -name '*.proto') - -python3 -m grpc_tools.protoc --version >/dev/null || { - echo "# Installing requirements-dev.txt ..." - pip3 install -q -r "$SCRIPT_DIR/requirements-dev.txt" -} - -echo "# Generating grpc stubs from: $DATABROKER_PROTO ..." -python3 -m grpc_tools.protoc \ - --python_out="$GEN_DIR" \ - --grpc_python_out="$GEN_DIR" \ - --proto_path="$DATABROKER_PROTO" \ - --mypy_out="$GEN_DIR" \ - $PROTO_FILES -set +x - -echo "# Generated files:" -find "$GEN_DIR" -type f -name '*.py' - -echo "# Replacing packages in $GEN_DIR" -find "$GEN_DIR" -type f -name '*.py' -print -exec sed -i 's/^from sdv.databroker.v1/from gen_proto.sdv.databroker.v1/g' {} ';' -find "$GEN_DIR" -type f -name '*.pyi' -print -exec sed -i 's/^import sdv.databroker.v1/import gen_proto.sdv.databroker.v1/g' {} ';' diff --git a/kuksa_databroker/lib/Cargo.lock b/kuksa_databroker/lib/Cargo.lock deleted file mode 100644 index 0f1cc9646..000000000 --- a/kuksa_databroker/lib/Cargo.lock +++ /dev/null @@ -1,1287 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "async-trait" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "autotools" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" -dependencies = [ - "cc", -] - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "cc" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "databroker-proto" -version = "0.4.3" -dependencies = [ - "prost", - "prost-types", - "protobuf-src", - "tonic", - "tonic-build", -] - -[[package]] -name = "either" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "kuksa" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "kuksa-common", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "kuksa-common" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "kuksa-sdv" -version = "0.4.3" -dependencies = [ - "databroker-proto", - "http", - "kuksa-common", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro2" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "protobuf-src" -version = "1.1.0+21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" -dependencies = [ - "autotools", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "serde" -version = "1.0.199" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.199" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio" -version = "1.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/kuksa_databroker/lib/Cargo.toml b/kuksa_databroker/lib/Cargo.toml deleted file mode 100644 index f87d347b8..000000000 --- a/kuksa_databroker/lib/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[workspace] -resolver = "2" - -members = [ - "common", - "kuksa", - "sdv" -] - -[workspace.dependencies] -databroker-proto = { path = "../databroker-proto" } -# prost has no features -prost = "0.11" -# prost-types has no features -prost-types = "0.11" -# tokio does not enable features by default -tokio = "1.17.0" -# tokio-stream has no features -tokio-stream = "0.1.8" -tonic = { version = "0.9.1", default-features = false } -tonic-build = { version = "0.8", default-features = false } diff --git a/kuksa_databroker/lib/common/Cargo.toml b/kuksa_databroker/lib/common/Cargo.toml deleted file mode 100644 index c39bdec20..000000000 --- a/kuksa_databroker/lib/common/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[package] -name = "kuksa-common" -version = "0.4.3" -authors = ["Eclipse KUKSA Project"] -edition = "2021" -license = "Apache-2.0" - -[dependencies] -databroker-proto = { workspace = true } -tonic = { workspace = true, features = ["transport", "channel"] } -tokio = { workspace = true, features = [ - "macros", -] } -tokio-stream = { workspace = true, features = ["sync"] } -http = "0.2.8" - -[lib] -name = "kuksa_common" -crate-type = ["lib"] -path = "src/lib.rs" - -[features] -default = ["tls"] -tls = ["tonic/tls"] diff --git a/kuksa_databroker/lib/common/src/lib.rs b/kuksa_databroker/lib/common/src/lib.rs deleted file mode 100644 index ac6a73905..000000000 --- a/kuksa_databroker/lib/common/src/lib.rs +++ /dev/null @@ -1,236 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::convert::TryFrom; - -use databroker_proto::kuksa::val::v1::Error; -use http::Uri; -use tokio_stream::wrappers::BroadcastStream; -use tonic::transport::Channel; - -#[derive(Debug)] -pub struct Client { - uri: Uri, - token: Option, - #[cfg(feature = "tls")] - tls_config: Option, - channel: Option, - connection_state_subs: Option>, -} - -#[derive(Clone)] -pub enum ConnectionState { - Connected, - Disconnected, -} - -#[derive(Debug, Clone)] -pub enum ClientError { - Connection(String), - Status(tonic::Status), - Function(Vec), -} - -impl std::error::Error for ClientError {} -impl std::fmt::Display for ClientError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ClientError::Connection(con) => f.pad(con), - ClientError::Status(status) => f.pad(&format!("{status}")), - ClientError::Function(err) => { - let formatted_result: String = err - .iter() - .map(|element| { - format!( - "code: {}, message: {}, reason: {}", - element.code, element.message, element.reason - ) - }) - .collect::>() - .join(", "); // Join the elements with a comma and space - - f.pad(&formatted_result) - } - } - } -} - -#[derive(Debug)] -pub enum TokenError { - MalformedTokenError(String), -} - -impl std::error::Error for TokenError {} -impl std::fmt::Display for TokenError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - TokenError::MalformedTokenError(msg) => f.pad(msg), - } - } -} - -pub fn to_uri(uri: impl AsRef) -> Result { - let uri = uri - .as_ref() - .parse::() - .map_err(|err| format!("{err}"))?; - let mut parts = uri.into_parts(); - - if parts.scheme.is_none() { - parts.scheme = Some("http".parse().expect("http should be valid scheme")); - } - - match &parts.authority { - Some(_authority) => { - // match (authority.port_u16(), port) { - // (Some(uri_port), Some(port)) => { - // if uri_port != port { - // parts.authority = format!("{}:{}", authority.host(), port) - // .parse::() - // .map_err(|err| format!("{}", err)) - // .ok(); - // } - // } - // (_, _) => {} - // } - } - None => return Err("No server uri specified".to_owned()), - } - parts.path_and_query = Some("".parse().expect("uri path should be empty string")); - tonic::transport::Uri::from_parts(parts).map_err(|err| format!("{err}")) -} - -impl Client { - pub fn new(uri: Uri) -> Self { - Client { - uri, - token: None, - #[cfg(feature = "tls")] - tls_config: None, - channel: None, - connection_state_subs: None, - } - } - - pub fn get_uri(&self) -> String { - self.uri.to_string() - } - - #[cfg(feature = "tls")] - pub fn set_tls_config(&mut self, tls_config: tonic::transport::ClientTlsConfig) { - self.tls_config = Some(tls_config); - } - - pub fn set_access_token(&mut self, token: impl AsRef) -> Result<(), TokenError> { - match tonic::metadata::AsciiMetadataValue::try_from(&format!("Bearer {}", token.as_ref())) { - Ok(token) => { - self.token = Some(token); - Ok(()) - } - Err(err) => Err(TokenError::MalformedTokenError(format!("{err}"))), - } - } - - pub fn is_connected(&self) -> bool { - self.channel.is_some() - } - - pub fn subscribe_to_connection_state(&mut self) -> BroadcastStream { - match &self.connection_state_subs { - Some(stream) => BroadcastStream::new(stream.subscribe()), - None => { - let (tx, rx1) = tokio::sync::broadcast::channel(1); - self.connection_state_subs = Some(tx); - BroadcastStream::new(rx1) - } - } - } - - async fn try_create_channel(&mut self) -> Result<&Channel, ClientError> { - #[cfg(feature = "tls")] - let mut builder = tonic::transport::Channel::builder(self.uri.clone()); - #[cfg(not(feature = "tls"))] - let builder = tonic::transport::Channel::builder(self.uri.clone()); - - #[cfg(feature = "tls")] - if let Some(tls_config) = &self.tls_config { - match builder.tls_config(tls_config.clone()) { - Ok(new_builder) => { - builder = new_builder; - } - Err(err) => { - return Err(ClientError::Connection(format!( - "Failed to configure TLS: {err}" - ))); - } - } - } - - match builder.connect().await { - Ok(channel) => { - if let Some(subs) = &self.connection_state_subs { - subs.send(ConnectionState::Connected).map_err(|err| { - ClientError::Connection(format!( - "Failed to notify connection state change: {err}" - )) - })?; - } - self.channel = Some(channel); - Ok(self.channel.as_ref().expect("Channel should exist")) - } - Err(err) => { - if let Some(subs) = &self.connection_state_subs { - subs.send(ConnectionState::Disconnected).unwrap_or_default(); - } - Err(ClientError::Connection(format!( - "Failed to connect to {}: {}", - self.uri, err - ))) - } - } - } - - pub async fn try_connect(&mut self) -> Result<(), ClientError> { - self.try_create_channel().await?; - Ok(()) - } - - pub async fn try_connect_to(&mut self, uri: tonic::transport::Uri) -> Result<(), ClientError> { - self.uri = uri; - self.try_create_channel().await?; - Ok(()) - } - - pub async fn get_channel(&mut self) -> Result<&Channel, ClientError> { - if self.channel.is_none() { - self.try_create_channel().await - } else { - match &self.channel { - Some(channel) => Ok(channel), - None => unreachable!(), - } - } - } - - pub fn get_auth_interceptor( - &mut self, - ) -> impl FnMut(tonic::Request<()>) -> Result, tonic::Status> + '_ { - move |mut req: tonic::Request<()>| { - if let Some(token) = &self.token { - // debug!("Inserting auth token: {:?}", token); - req.metadata_mut().insert("authorization", token.clone()); - } - Ok(req) - } - } -} diff --git a/kuksa_databroker/lib/databroker-examples/examples/perf_setter.rs b/kuksa_databroker/lib/databroker-examples/examples/perf_setter.rs deleted file mode 100644 index db803e0c2..000000000 --- a/kuksa_databroker/lib/databroker-examples/examples/perf_setter.rs +++ /dev/null @@ -1,216 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::sdv::databroker as proto; - -use prost_types::Timestamp; - -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; - -use std::collections::HashMap; -use std::env; -use std::time::{Instant, SystemTime}; - -const DEFAULT_ITERATIONS: i32 = 1000; -const DEFAULT_NTH_MESSAGE: i32 = 1; - -fn create_payload(value: &str, id: i32) -> proto::v1::StreamDatapointsRequest { - let ts = Timestamp::from(SystemTime::now()); - proto::v1::StreamDatapointsRequest { - datapoints: HashMap::from([( - id, - proto::v1::Datapoint { - timestamp: Some(ts), - value: Some(proto::v1::datapoint::Value::StringValue(value.to_string())), - }, - )]), - } -} - -async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { - let connect = tonic::transport::Channel::from_static("http://127.0.0.1:55555") - .connect() - .await; - match connect { - Ok(channel) => { - let mut client = proto::v1::collector_client::CollectorClient::with_interceptor( - channel, - |mut req: tonic::Request<()>| { - req.metadata_mut().append("authorization", - "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicHJvdmlkZSBjcmVhdGUifQ.h7F2q5pXJ0VAGKQJQKrRwj_RZIhWRb5y6_7YXwhnAv-sH5tk_LSXy7UQPEE2pO8Bzp2xCOD3gjkulJZZ49Xk-0sLgedb9YLgONfgcsySaknOTLB0PSbdBMVXhtfuNyTN9RMoeW4gLsNaitVw-_QM027nmaqzaQmgNb8GyBqonqrZD8jjFTf2e6wHYg1DuvxooMoI1gn8r_weXYmK8ksBJrL4097FD5jghF9mJKzKG25oM6wl2vkibmv3l1ZmHdilA_QIbt7ZXAh0VO8NVwUfWWxitimSs27w3CE2wvcwWI7hgLHOR2wJEqkgaMaOckVbkbJPXDrWQz-uDyCwOr2oICpUELOp1j-lbHTIH1dunmilldLMJlVbatMDmYtGYDmvZQ470aAH-Df_fN4WtoxdWHQekNBjr0TIM-vP1-uucFPprMWFtUjjejwQVNVBRz_HaZiOObt4jku0VHv1fP3y7MJmJ6M--RSQlGNnvtKzJXG9exeN3wmkyBpdnVFQ4s_EUn88kkneiPZAas7zAhRQhBjwLS7n0j761wXAUrEQPQ0YQ7AhhopZLmrhiJeGAoZQ5kazUb8p2qIiIroLDGoO6gvd6RK_M-3EJ3mGaUdqrEKxWk9-r5lu6UcE1Zl7XXr_AHD2sD9mwVpuFJ_mYHN5hvvcZUjkmrBdGTkryAfatwY" - .parse::() - .unwrap() - ); - Ok(req) - }, - ); - - let datapoint1_id = match client - .register_datapoints(tonic::Request::new(proto::v1::RegisterDatapointsRequest { - list: vec![proto::v1::RegistrationMetadata { - name: "Vehicle.ADAS.ABS.Error".to_owned(), - description: "Vehicle.ADAS.ABS.Error".to_owned(), - data_type: proto::v1::DataType::String as i32, - change_type: proto::v1::ChangeType::Continuous as i32, - }], - })) - .await - { - Ok(metadata) => metadata.into_inner().results["Vehicle.ADAS.ABS.Error"], - Err(err) => { - println!("Couldn't retrieve metadata: {err:?}"); - -1 - } - }; - - if datapoint1_id == -1 { - return; - } - let (tx, rx) = mpsc::channel(10); - let now = Instant::now(); - - let sender = tokio::spawn(async move { - match client.stream_datapoints(ReceiverStream::new(rx)).await { - Ok(response) => { - let mut stream = response.into_inner(); - - while let Ok(message) = stream.message().await { - match message { - Some(message) => { - for error in message.errors { - println!( - "Error setting datapoint {}: {:?}", - error.0, - proto::v1::DatapointError::from_i32(error.1) - ) - } - } - None => { - break; - } - } - } - // match PropertyStatus::from_i32(message.status) { - // Some(status) => { - // println!("-> status: {:?}", status) - // } - // None => println!("-> status: Unknown"), - // } - } - Err(err) => { - // println!("-> status: {}",code_to_text(&err.code())); - println!("{}", err.message()); - } - } - }); - - let feeder = tokio::spawn(async move { - // send start message - match tx.send(create_payload("start", datapoint1_id)).await { - Ok(_) => { - eprintln!("START"); - } - Err(err) => eprint!("{err}"), - }; - - let mut n: i32 = 0; - let mut n_id: i32 = 0; - - // send event messages - for i in 0..iterations { - // Every N:th message is of the subscribed type - let id = if (n % n_th_message) == 0 { - datapoint1_id - } else { - 11 - }; - - match tx.send(create_payload("event", id)).await { - Ok(_) => { - if (i % 1000) == 0 { - // eprint!("#"); - let seconds = now.elapsed().as_secs_f64(); - eprint!("\r{} messages sent ({:.1} / s)", n, n as f64 / seconds); - } - if id == datapoint1_id { - n_id += 1; - } - n += 1; - } - Err(err) => eprint!("{err}"), - }; - } - - // send end message - match tx.send(create_payload("end", datapoint1_id)).await { - Ok(_) => { - eprintln!("\rEND "); - } - Err(err) => eprint!("{err}"), - }; - - (n, n_id) - }); - - let (n, n_id) = feeder.await.unwrap(); - match sender.await { - Ok(_) => {} - Err(err) => eprint!("{err}"), - }; - - let seconds = now.elapsed().as_secs_f64(); - println!( - "Pushed {} total messages ({:.1} / s)", - n, - n as f64 / seconds - ); - println!( - "Pushed {} matching messages ({:.1} / s)", - n_id, - n_id as f64 / seconds - ); - println!("Completed in {seconds:.3} s"); - } - Err(err) => { - println!("{err}"); - } - } -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let args: Vec = env::args().collect(); - let iterations = match args.get(1) { - Some(arg1) => match arg1.parse::() { - Ok(number) => number, - Err(_) => DEFAULT_ITERATIONS, - }, - None => DEFAULT_ITERATIONS, - }; - - let queue_size = match args.get(2) { - Some(arg1) => match arg1.parse::() { - Ok(number) => number, - Err(_) => DEFAULT_NTH_MESSAGE, - }, - None => DEFAULT_NTH_MESSAGE, - }; - - println!("INPUT: Set {iterations} times"); - - // run_set_test(iterations).await; - run_streaming_set_test(iterations, queue_size).await; - - Ok(()) -} diff --git a/kuksa_databroker/lib/databroker-examples/examples/perf_subscriber.rs b/kuksa_databroker/lib/databroker-examples/examples/perf_subscriber.rs deleted file mode 100644 index 1cbd036b2..000000000 --- a/kuksa_databroker/lib/databroker-examples/examples/perf_subscriber.rs +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use databroker_proto::sdv::databroker as proto; - -use std::time::Instant; - -#[tokio::main] -async fn main() -> Result<(), Box> { - match tonic::transport::Channel::from_static("http://127.0.0.1:55555") - .connect() - .await - { - Ok(channel) => { - let mut client = proto::v1::broker_client::BrokerClient::with_interceptor( - channel, - |mut req: tonic::Request<()>| { - req.metadata_mut().append("authorization", - "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsb2NhbCBkZXYiLCJpc3MiOiJjcmVhdGVUb2tlbi5weSIsImF1ZCI6WyJrdWtzYS52YWwiXSwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3NjcyMjU1OTksInNjb3BlIjoicmVhZCJ9.P6tJPRSJWB51UOFDFs8qQ-lGqb1NoWgCekHUKyMiYcs8sR3FGVKSRjSkcqv1tXOlILvqhUwyuTKui25_kFKkTPv47GI0xAqcXtaTmDwHAWZHFC6HWGWGXohu7XvURrim5kMRVHy_VGlzasGgVap0JFk3wmaY-nyFYL_PLDjvGjIQuOwFiUtKK1PfiKviZKyc5EzPUEAoHxFL_BSOsTdDDcaydFe9rSKJzpYrj7qXY0hMJCje2BUGlSUIttR95aSjOZflSxiGystWHME8fKMmDERAx749Jpt37M3taCxBsUzER5olPz65MGzFSikfC-jH_KGmJ4zNYS65_OM1a-CPfW7Ts__pyAXxFULNMHRMIfh8Wiig4UcooMy_ZJO_DN2rq95XdaBbzRua5mxvO2wM6iu5kv4lhNxhjVNGuWFRLLJ_icBUZlvAuC3eqp66B-Y3jJNI0cSnIvsVX8YFVS3ebW8tf40OdeVou8fWZPcQsFAAafBhIxNOW8FbLZ9sRvQ-FGwZy-GyF52IJ5ZKeGfAkeEh9ZLIcyJ2YlGp4q0EOKIdwIBsWfCFtZbAvi2ornO3XvJm94NBqprpvQYN_IB7yyRxDduLjNKqqcFqnrlWYI-ZhvghWH2rEblplgHZdyVD1G9Mbv0_zdNTKFs6J7IP96aV6-4hBOt3kROlS1G7ObA" - .parse::() - .unwrap() - ); - Ok(req) - }, - ); - let mut n: i32 = 0; - - let args = tonic::Request::new(proto::v1::SubscribeRequest { - query: String::from("SELECT Vehicle.ADAS.ABS.Error"), - }); - - let mut now = Instant::now(); - // let mut last_status = Instant::now(); - - match client.subscribe(args).await { - Ok(response) => { - let mut stream = response.into_inner(); - let mut running = true; - let mut started = false; - while running { - if let Some(update) = stream.message().await? { - for (_id, datapoint) in update.fields { - if let Some(value) = datapoint.value { - match value { - proto::v1::datapoint::Value::FailureValue(reason) => { - if started { - eprintln!("-> Failure: {reason:?}"); - } - } - proto::v1::datapoint::Value::StringValue(string_value) => { - match string_value.as_str() { - "start" => { - eprintln!("START"); - started = true; - now = Instant::now(); - } - "end" => { - if started { - running = false; - let seconds = now.elapsed().as_secs_f64(); - // eprintln!("\rReceived {} messages ({:.1} / s)", n, n as f64 / seconds); - eprintln!("\rEND "); - eprintln!( - "{} messages received ({:.1} / s)", - n, - n as f64 / seconds - ); - eprintln!("Completed in {seconds:.3} s"); - } - } - _ => { - started = true; - n += 1; - if (n % 1000) == 0 { - let seconds = now.elapsed().as_secs_f64(); - eprint!( - "\rReceived {} messages ({:.1} / s)", - n, - n as f64 / seconds - ); - } - } - } - } - _ => eprintln!("-> Other value"), - } - } else { - eprintln!("-> Empty datapoint value"); - } - // } - } - } else { - eprintln!("Server gone. Subscription stopped"); - running = false; - } - } - // if let Ok(trailers) = stream.trailers().await { - // eprintln!("{:?}", trailers); - // } - } - Err(err) => { - eprintln!("{}", err.message()); - } - } - } - Err(err) => { - eprintln!("{err}"); - } - } - - Ok(()) -} diff --git a/kuksa_databroker/lib/databroker-examples/src/lib.rs b/kuksa_databroker/lib/databroker-examples/src/lib.rs deleted file mode 100644 index 57e46ce14..000000000 --- a/kuksa_databroker/lib/databroker-examples/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2022 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ diff --git a/kuksa_databroker/lib/kuksa/Cargo.toml b/kuksa_databroker/lib/kuksa/Cargo.toml deleted file mode 100644 index 85baa3680..000000000 --- a/kuksa_databroker/lib/kuksa/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[package] -name = "kuksa" -version = "0.4.3" -authors = ["Eclipse KUKSA Project"] -edition = "2021" -license = "Apache-2.0" - -[dependencies] -kuksa-common = { path = "../common"} -databroker-proto = { workspace = true } -tonic = { workspace = true, features = ["transport", "channel"] } -tokio = { workspace = true, features = [ - "macros", -] } -tokio-stream = { workspace = true, features = ["sync"] } -http = "0.2.8" - -[lib] -name = "kuksa" -crate-type = ["lib"] -path = "src/lib.rs" - -[features] -default = ["tls"] -tls = ["tonic/tls"] diff --git a/kuksa_databroker/lib/kuksa/src/lib.rs b/kuksa_databroker/lib/kuksa/src/lib.rs deleted file mode 100644 index a2beec628..000000000 --- a/kuksa_databroker/lib/kuksa/src/lib.rs +++ /dev/null @@ -1,356 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use http::Uri; -use std::collections::HashMap; - -use databroker_proto::kuksa::val::{self as proto, v1::DataEntry}; - -use kuksa_common::{Client, ClientError}; - -#[derive(Debug)] -pub struct KuksaClient { - pub basic_client: Client, -} - -impl KuksaClient { - pub fn new(uri: Uri) -> Self { - KuksaClient { - basic_client: Client::new(uri), - } - } - - async fn set(&mut self, entry: DataEntry, _fields: Vec) -> Result<(), ClientError> { - let mut client = proto::v1::val_client::ValClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - let set_request = proto::v1::SetRequest { - updates: vec![proto::v1::EntryUpdate { - entry: Some(entry), - fields: _fields, - }], - }; - match client.set(set_request).await { - Ok(response) => { - let message = response.into_inner(); - let mut errors: Vec = Vec::new(); - if let Some(err) = message.error { - errors.push(err); - } - for error in message.errors { - if let Some(err) = error.error { - errors.push(err); - } - } - if errors.is_empty() { - Ok(()) - } else { - Err(ClientError::Function(errors)) - } - } - Err(err) => Err(ClientError::Status(err)), - } - } - - async fn get( - &mut self, - path: &str, - view: proto::v1::View, - _fields: Vec, - ) -> Result, ClientError> { - let mut client = proto::v1::val_client::ValClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - - let get_request = proto::v1::GetRequest { - entries: vec![proto::v1::EntryRequest { - path: path.to_string(), - view: view.into(), - fields: _fields, - }], - }; - - match client.get(get_request).await { - Ok(response) => { - let message = response.into_inner(); - let mut errors = Vec::new(); - if let Some(err) = message.error { - errors.push(err); - } - for error in message.errors { - if let Some(err) = error.error { - errors.push(err); - } - } - if !errors.is_empty() { - Err(ClientError::Function(errors)) - } else { - // since there is only one DataEntry in the vector return only the according DataEntry - Ok(message.entries.clone()) - } - } - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn get_metadata(&mut self, paths: Vec<&str>) -> Result, ClientError> { - let mut metadata_result = Vec::new(); - - for path in paths { - match self - .get( - path, - proto::v1::View::Metadata, - vec![proto::v1::Field::Metadata.into()], - ) - .await - { - Ok(mut entry) => metadata_result.append(&mut entry), - Err(err) => return Err(err), - } - } - - Ok(metadata_result) - } - - pub async fn get_current_values( - &mut self, - paths: Vec, - ) -> Result, ClientError> { - let mut get_result = Vec::new(); - - for path in paths { - match self - .get( - &path, - proto::v1::View::CurrentValue, - vec![ - proto::v1::Field::Value.into(), - proto::v1::Field::Metadata.into(), - ], - ) - .await - { - Ok(mut entry) => get_result.append(&mut entry), - Err(err) => return Err(err), - } - } - - Ok(get_result) - } - - pub async fn get_target_values( - &mut self, - paths: Vec<&str>, - ) -> Result, ClientError> { - let mut get_result = Vec::new(); - - for path in paths { - match self - .get( - path, - proto::v1::View::TargetValue, - vec![ - proto::v1::Field::ActuatorTarget.into(), - proto::v1::Field::Metadata.into(), - ], - ) - .await - { - Ok(mut entry) => get_result.append(&mut entry), - Err(err) => return Err(err), - } - } - - Ok(get_result) - } - - pub async fn set_current_values( - &mut self, - datapoints: HashMap, - ) -> Result<(), ClientError> { - for (path, datapoint) in datapoints { - match self - .set( - proto::v1::DataEntry { - path: path.clone(), - value: Some(datapoint), - actuator_target: None, - metadata: None, - }, - vec![ - proto::v1::Field::Value.into(), - proto::v1::Field::Path.into(), - ], - ) - .await - { - Ok(_) => { - continue; - } - Err(err) => return Err(err), - } - } - - Ok(()) - } - - pub async fn set_target_values( - &mut self, - datapoints: HashMap, - ) -> Result<(), ClientError> { - for (path, datapoint) in datapoints { - match self - .set( - proto::v1::DataEntry { - path: path.clone(), - value: None, - actuator_target: Some(datapoint), - metadata: None, - }, - vec![ - proto::v1::Field::ActuatorTarget.into(), - proto::v1::Field::Path.into(), - ], - ) - .await - { - Ok(_) => { - continue; - } - Err(err) => return Err(err), - } - } - - Ok(()) - } - - pub async fn set_metadata( - &mut self, - metadatas: HashMap, - ) -> Result<(), ClientError> { - for (path, metadata) in metadatas { - match self - .set( - proto::v1::DataEntry { - path: path.clone(), - value: None, - actuator_target: None, - metadata: Some(metadata), - }, - vec![ - proto::v1::Field::Metadata.into(), - proto::v1::Field::Path.into(), - ], - ) - .await - { - Ok(_) => { - continue; - } - Err(err) => return Err(err), - } - } - - Ok(()) - } - - pub async fn subscribe_current_values( - &mut self, - paths: Vec<&str>, - ) -> Result, ClientError> { - let mut client = proto::v1::val_client::ValClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - - let mut entries = Vec::new(); - for path in paths { - entries.push(proto::v1::SubscribeEntry { - path: path.to_string(), - view: proto::v1::View::CurrentValue.into(), - fields: vec![ - proto::v1::Field::Value.into(), - proto::v1::Field::Metadata.into(), - ], - }) - } - - let req = proto::v1::SubscribeRequest { entries }; - - match client.subscribe(req).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } - - //masking subscribe curent values with subscribe due to plugability - pub async fn subscribe( - &mut self, - paths: Vec<&str>, - ) -> Result, ClientError> { - self.subscribe_current_values(paths).await - } - - pub async fn subscribe_target_values( - &mut self, - paths: Vec<&str>, - ) -> Result, ClientError> { - let mut client = proto::v1::val_client::ValClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - let mut entries = Vec::new(); - for path in paths { - entries.push(proto::v1::SubscribeEntry { - path: path.to_string(), - view: proto::v1::View::TargetValue.into(), - fields: vec![proto::v1::Field::ActuatorTarget.into()], - }) - } - - let req = proto::v1::SubscribeRequest { entries }; - - match client.subscribe(req).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn subscribe_metadata( - &mut self, - paths: Vec, - ) -> Result, ClientError> { - let mut client = proto::v1::val_client::ValClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - let mut entries = Vec::new(); - for path in paths { - entries.push(proto::v1::SubscribeEntry { - path: path.to_string(), - view: proto::v1::View::Metadata.into(), - fields: vec![proto::v1::Field::Metadata.into()], - }) - } - - let req = proto::v1::SubscribeRequest { entries }; - - match client.subscribe(req).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } -} diff --git a/kuksa_databroker/lib/sdv/Cargo.toml b/kuksa_databroker/lib/sdv/Cargo.toml deleted file mode 100644 index 0531f797d..000000000 --- a/kuksa_databroker/lib/sdv/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -#******************************************************************************** -# Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ - -[package] -name = "kuksa-sdv" -version = "0.4.3" -authors = ["Eclipse KUKSA Project"] -edition = "2021" -license = "Apache-2.0" - -[dependencies] -kuksa-common = { path = "../common"} -databroker-proto = { workspace = true } -tonic = { workspace = true, features = ["transport", "channel"] } -tokio = { workspace = true, features = [ - "macros", -] } -tokio-stream = { workspace = true, features = ["sync"] } -http = "0.2.8" - -[lib] -name = "kuksa_sdv" -crate-type = ["lib"] -path = "src/lib.rs" - -[features] -default = ["tls"] -tls = ["tonic/tls"] diff --git a/kuksa_databroker/lib/sdv/src/lib.rs b/kuksa_databroker/lib/sdv/src/lib.rs deleted file mode 100644 index d011b1cde..000000000 --- a/kuksa_databroker/lib/sdv/src/lib.rs +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************************** -* Copyright (c) 2023 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License 2.0 which is available at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ - -use std::collections::HashMap; - -use databroker_proto::sdv::databroker as proto; -use http::Uri; -use kuksa_common::{Client, ClientError}; - -pub struct SDVClient { - pub basic_client: Client, -} - -impl SDVClient { - pub fn new(uri: Uri) -> Self { - SDVClient { - basic_client: Client::new(uri), - } - } - - pub async fn get_metadata( - &mut self, - paths: Vec, - ) -> Result, ClientError> { - let mut client = proto::v1::broker_client::BrokerClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - // Empty vec == all property metadata - let args = tonic::Request::new(proto::v1::GetMetadataRequest { names: paths }); - match client.get_metadata(args).await { - Ok(response) => { - let message = response.into_inner(); - Ok(message.list) - } - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn get_datapoints( - &mut self, - paths: Vec>, - ) -> Result< - HashMap, - ClientError, - > { - let mut client = proto::v1::broker_client::BrokerClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - let args = tonic::Request::new(proto::v1::GetDatapointsRequest { - datapoints: paths.iter().map(|path| path.as_ref().into()).collect(), - }); - match client.get_datapoints(args).await { - Ok(response) => { - let message = response.into_inner(); - Ok(message.datapoints) - } - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn set_datapoints( - &mut self, - datapoints: HashMap, - ) -> Result { - let args = tonic::Request::new(proto::v1::SetDatapointsRequest { datapoints }); - let mut client = proto::v1::broker_client::BrokerClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - match client.set_datapoints(args).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn subscribe( - &mut self, - query: String, - ) -> Result, ClientError> { - let mut client = proto::v1::broker_client::BrokerClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - let args = tonic::Request::new(proto::v1::SubscribeRequest { query }); - - match client.subscribe(args).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } - - pub async fn update_datapoints( - &mut self, - datapoints: HashMap, - ) -> Result { - let mut client = proto::v1::collector_client::CollectorClient::with_interceptor( - self.basic_client.get_channel().await?.clone(), - self.basic_client.get_auth_interceptor(), - ); - - let request = tonic::Request::new(proto::v1::UpdateDatapointsRequest { datapoints }); - match client.update_datapoints(request).await { - Ok(response) => Ok(response.into_inner()), - Err(err) => Err(ClientError::Status(err)), - } - } -} diff --git a/kuksa_databroker/prepare_release.sh b/kuksa_databroker/prepare_release.sh deleted file mode 100755 index 3615edb62..000000000 --- a/kuksa_databroker/prepare_release.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -#******************************************************************************** -# Copyright (c) 2022 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License 2.0 which is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -#*******************************************************************************/ -set -e - -if [ "$#" -ne 1 ]; then - echo "Usage: $0 " - exit 1 -fi - -VERSION_REGEX="[0-9]+\.[0-9]+(\.[0-9]+)?" -VERSION="$1" - -if [ "$(echo "$1" | sed -E "s/$VERSION_REGEX//")" ]; then - echo " should be of the form MAJOR.MINOR[.PATCH]" - exit 1 -fi - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -DATA_BROKER_ROOT="$SCRIPT_DIR" - -# Update Cargo.toml versions. -sed -i -E "s/^version = \"${VERSION_REGEX}\"$/version = \"${VERSION}\"/" \ - "$DATA_BROKER_ROOT/databroker/Cargo.toml" \ - "$DATA_BROKER_ROOT/databroker-api/Cargo.toml" \ - "$DATA_BROKER_ROOT/databroker-cli/Cargo.toml" \ - "$DATA_BROKER_ROOT/databroker-examples/Cargo.toml" - -# Create release commit and tag it -#git commit -a -m "Release ${VERSION}" -#git tag -a "v${VERSION}" -m "Release ${VERSION}" diff --git a/kuksa_databroker/proto/kuksa/val/v1/README.md b/kuksa_databroker/proto/kuksa/val/v1/README.md deleted file mode 120000 index 00b5e095f..000000000 --- a/kuksa_databroker/proto/kuksa/val/v1/README.md +++ /dev/null @@ -1 +0,0 @@ -../../../../../proto/kuksa/val/v1/README.md \ No newline at end of file diff --git a/kuksa_databroker/proto/kuksa/val/v1/types.proto b/kuksa_databroker/proto/kuksa/val/v1/types.proto deleted file mode 120000 index bc9b0b78c..000000000 --- a/kuksa_databroker/proto/kuksa/val/v1/types.proto +++ /dev/null @@ -1 +0,0 @@ -../../../../../proto/kuksa/val/v1/types.proto \ No newline at end of file diff --git a/kuksa_databroker/proto/kuksa/val/v1/val.proto b/kuksa_databroker/proto/kuksa/val/v1/val.proto deleted file mode 120000 index b88b89e2f..000000000 --- a/kuksa_databroker/proto/kuksa/val/v1/val.proto +++ /dev/null @@ -1 +0,0 @@ -../../../../../proto/kuksa/val/v1/val.proto \ No newline at end of file diff --git a/kuksa_databroker/proto/sdv/databroker/v1/README.md b/kuksa_databroker/proto/sdv/databroker/v1/README.md deleted file mode 100644 index 3f4d97ce6..000000000 --- a/kuksa_databroker/proto/sdv/databroker/v1/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# sdv.databroker.v1 protobuf API - -This directory contain a Protobuf API supported by KUKSA.val Databroker. - -As of today KUKSA.val Databroker supports both this API and the -[kuksa.val.v1](https://github.com/eclipse/kuksa.val/tree/master/proto/kuksa/val/v1) API. -The [kuksa.val.v1](https://github.com/eclipse/kuksa.val/tree/master/proto/kuksa/val/v1) API is the newer API and is still -in development. It does not yet support all features supported by this API. - -This API may in the future be deprecated. It is recommended to use -the [kuksa.val.v1](https://github.com/eclipse/kuksa.val/tree/master/proto/kuksa/val/v1) API, unless you need -functionality currently only provided by this API. diff --git a/kuksa_databroker/proto/sdv/databroker/v1/broker.proto b/kuksa_databroker/proto/sdv/databroker/v1/broker.proto deleted file mode 100644 index f8ffaf802..000000000 --- a/kuksa_databroker/proto/sdv/databroker/v1/broker.proto +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -syntax = "proto3"; - -package sdv.databroker.v1; - -import "sdv/databroker/v1/types.proto"; - -service Broker { - // Request a set of datapoints (values) - // - // Returns a list of requested data points. - // - // InvalidArgument is returned if the request is malformed. - rpc GetDatapoints(GetDatapointsRequest) returns (GetDatapointsReply); - - // Set a datapoint (values) - rpc SetDatapoints(SetDatapointsRequest) returns (SetDatapointsReply); - - // Subscribe to a set of data points or conditional expressions - // using the Data Broker Query Syntax (described in QUERY.md) - // - // Returns a stream of replies. - // - // InvalidArgument is returned if the request is malformed. - rpc Subscribe(SubscribeRequest) returns (stream SubscribeReply); - - // Request the metadata of a set of datapoints - // - // Returns metadata of the requested data points that exist. - rpc GetMetadata(GetMetadataRequest) returns (GetMetadataReply); -} - -message GetDatapointsRequest { - // A list of requested data points. - repeated string datapoints = 1; -} - -message GetDatapointsReply { - // Contains the values of the requested data points. - // If a requested data point is not available, the corresponding Datapoint - // will have the respective failure value set. - map datapoints = 1; -} - -message SetDatapointsRequest { - // A map of data points to set - map datapoints = 1; -} - -message SetDatapointsReply { - // A map of errors (if any) - map errors = 1; -} - -message SubscribeRequest { - // Subscribe to a set of data points (or expressions) described - // by the provided query. - // The query syntax is a subset of SQL and is described in more - // detail in the QUERY.md file. - string query = 2; -} - -message SubscribeReply { - // Contains the fields specified by the query. - // If a requested data point value is not available, the corresponding - // Datapoint will have it's respective failure value set. - map fields = 1; -} - -message GetMetadataRequest { - // Request metadata for a list of data points referenced by their names. - // e.g. "Vehicle.Cabin.Seat.Row1.Pos1.Position" or "Vehicle.Speed". - // - // If no names are provided, metadata for all known data points will be - // returned. - repeated string names = 1; -} - -message GetMetadataReply { - // Contains metadata of the requested data points. If a data point - // doesn't exist (i.e. not known to the Data Broker) the corresponding - // Metadata isn't part of the returned list. - repeated Metadata list = 1; -} diff --git a/kuksa_databroker/proto/sdv/databroker/v1/collector.proto b/kuksa_databroker/proto/sdv/databroker/v1/collector.proto deleted file mode 100644 index c67a5def1..000000000 --- a/kuksa_databroker/proto/sdv/databroker/v1/collector.proto +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -syntax = "proto3"; - -import "sdv/databroker/v1/types.proto"; - -package sdv.databroker.v1; - -service Collector { - // Register new datapoint (metadata) - // - // If the registration of at least one of the passed data point fails, the overall registration - // is rejected and the gRPC status code ABORTED is returned (to indicate the "aborted" registration). - // The details, which data point(s) caused the failure and the reason, is passed in back in human- - // readable form in the status message. Possible failure resaons are: - // * PERMISSION_DENIED - Not allowed to register this name - // * ALREADY_REGISTERED - The data point is already registered by some other feeder - // * RE_REGISTRATION_MISMATCH - Already registered by this feeder but with differing metadata - // * INVALID_NAME - The passed name of the datapoint has an invalid structure - // * INVALID_VALUE_TYPE - The passed ValueType is not supported - // * INVALID_CHANGE_TYPE - The passed ChangeType is not supported - rpc RegisterDatapoints(RegisterDatapointsRequest) returns (RegisterDatapointsReply); - - // Provide a set of updated datapoint values to the broker. - // This is the unary equivalent of `StreamDatapoints` below and is better suited for cases - // where the frequency of updates is rather low. - // - // NOTE: The values provided in a single request are handled as a single update in the - // data broker. This ensures that any clients requesting (or subscribing to) a set of - // datapoints will get a consistent update, i.e. that either all values are updated or - // none are. - // - // Returns: any errors encountered updating the datapoints - // - rpc UpdateDatapoints(UpdateDatapointsRequest) returns (UpdateDatapointsReply); - - // Provide a stream with updated datapoint values to the broker. - // This is the streaming equivalent of `UpdateDatapoints` above and is better suited for - // cases where the frequency of updates is high. - // - // NOTE: The values provided in a single request are handled as a single update in the - // data broker. This ensures that any clients requesting (or subscribing to) a set of - // datapoints will get a consistent update, i.e. that either all values are updated or - // none are. - // - // Returns: any errors encountered updating the datapoints - // - rpc StreamDatapoints(stream StreamDatapointsRequest) returns (stream StreamDatapointsReply); -} - -message UpdateDatapointsRequest { - map datapoints = 1; -} - -message UpdateDatapointsReply { - map errors = 1; // If empty, everything went well -} - -message StreamDatapointsRequest { - map datapoints = 1; -} - -message StreamDatapointsReply { - map errors = 1; // If empty, everything went well -} - -message RegisterDatapointsRequest { - repeated RegistrationMetadata list = 1; -} - -message RegistrationMetadata { - // Name of the data point - // (e.g. "Vehicle.Cabin.Seat.Row1.Pos1.Position" or "Vehicle.Speed") - string name = 1; - DataType data_type = 2; - string description = 3; - ChangeType change_type = 4; - - // int32 min_update_hz = 10; // Only for CONTINUOUS - // int32 max_update_hz = 11; // Only for CONTINUOUS -}; - -message RegisterDatapointsReply { - // Maps each data point name passed in RegisterDatapointsRequest to a data point id - map results = 1; -} diff --git a/kuksa_databroker/proto/sdv/databroker/v1/types.proto b/kuksa_databroker/proto/sdv/databroker/v1/types.proto deleted file mode 100644 index 6790377c3..000000000 --- a/kuksa_databroker/proto/sdv/databroker/v1/types.proto +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -syntax = "proto3"; - -import "google/protobuf/timestamp.proto"; - -package sdv.databroker.v1; - -// Data type of a signal -// -// Protobuf doesn't support int8, int16, uint8 or uint16. -// These are mapped to sint32 and uint32 respectively. -// -enum DataType { - STRING = 0; - BOOL = 1; - INT8 = 2; - INT16 = 3; - INT32 = 4; - INT64 = 5; - UINT8 = 6; - UINT16 = 7; - UINT32 = 8; - UINT64 = 9; - FLOAT = 10; - DOUBLE = 11; - STRING_ARRAY = 20; - BOOL_ARRAY = 21; - INT8_ARRAY = 22; - INT16_ARRAY = 23; - INT32_ARRAY = 24; - INT64_ARRAY = 25; - UINT8_ARRAY = 26; - UINT16_ARRAY = 27; - UINT32_ARRAY = 28; - UINT64_ARRAY = 29; - FLOAT_ARRAY = 30; - DOUBLE_ARRAY = 31; -} - -enum DatapointError { - UNKNOWN_DATAPOINT = 0; - INVALID_TYPE = 1; - ACCESS_DENIED = 2; - INTERNAL_ERROR = 3; - OUT_OF_BOUNDS = 4; -} - -enum EntryType { - ENTRY_TYPE_UNSPECIFIED = 0; - ENTRY_TYPE_SENSOR = 1; - ENTRY_TYPE_ACTUATOR = 2; - ENTRY_TYPE_ATTRIBUTE = 3; -} - -enum ChangeType { - STATIC = 0; // Value never changes - ON_CHANGE = 1; // Updates are provided every time the value changes (i.e. - // window is open / closed) - CONTINUOUS = 2; // Value is updated continuously. Broker needs to tell - // provider the preferred (update) frequency. -} - -message StringArray { - repeated string values = 1; -} - -message BoolArray { - repeated bool values = 1; -} - -message Int32Array { - repeated sint32 values = 1; -} - -message Int64Array { - repeated sint64 values = 1; -} - -message Uint32Array { - repeated uint32 values = 1; -} - -message Uint64Array { - repeated uint64 values = 1; -} - -message FloatArray { - repeated float values = 1; -} - -message DoubleArray { - repeated double values = 1; -} - -message Datapoint { - // Timestamp of the value - google.protobuf.Timestamp timestamp = 1; - - // values - oneof value { - Failure failure_value = 10; - string string_value = 11; - bool bool_value = 12; - sint32 int32_value = 13; - sint64 int64_value = 14; - uint32 uint32_value = 15; - uint64 uint64_value = 16; - float float_value = 17; - double double_value = 18; - StringArray string_array = 21; - BoolArray bool_array = 22; - Int32Array int32_array = 23; - Int64Array int64_array = 24; - Uint32Array uint32_array = 25; - Uint64Array uint64_array = 26; - FloatArray float_array = 27; - DoubleArray double_array = 28; - } - - enum Failure { - // The data point is known, but doesn't have a valid value - INVALID_VALUE = 0; - // The data point is known, but no value is available - NOT_AVAILABLE = 1; - // Unknown datapoint - UNKNOWN_DATAPOINT = 2; - // Access denied - ACCESS_DENIED = 3; - // Unexpected internal error - INTERNAL_ERROR = 4; - } -} - -message Metadata { - // Id to be used in "get" and "subscribe" requests. Ids stay valid during - // one power cycle, only. - int32 id = 1; - EntryType entry_type = 2; - string name = 4; - DataType data_type = 5; - ChangeType change_type = 6; // CONTINUOUS or STATIC or ON_CHANGE - string description = 7; - - // int32 min_update_hz = 10; // Only for CONTINUOUS - // int32 max_update_hz = 11; // Only for CONTINUOUS -}; diff --git a/proto/kuksa/val/v1/README.md b/proto/kuksa/val/v1/README.md deleted file mode 100644 index 8284bfd17..000000000 --- a/proto/kuksa/val/v1/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# kuksa.val.v1 protobuf API - -This directory contain a Protobuf API supported by KUKSA.val Databroker, KUKSA.val Python Client and KUKSA.val Go Client. - -This API is under development and will eventually replace the -[sdv.databroker.v1](https://github.com/eclipse/kuksa.val/tree/master/kuksa_databroker/proto/sdv/databroker/v1) API. diff --git a/proto/kuksa/val/v1/types.proto b/proto/kuksa/val/v1/types.proto deleted file mode 100644 index 8914e7aff..000000000 --- a/proto/kuksa/val/v1/types.proto +++ /dev/null @@ -1,288 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -syntax = "proto3"; - -// I added V1 as in databroker. Is this good practice? -package kuksa.val.v1; -import "google/protobuf/timestamp.proto"; - -option go_package = "kuksa/val/v1"; - -// Describes a VSS entry -// When requesting an entry, the amount of information returned can -// be controlled by specifying either a `View` or a set of `Field`s. -message DataEntry { - // Defines the full VSS path of the entry. - string path = 1; // [field: FIELD_PATH] - - // The value (datapoint) - Datapoint value = 2; // [field: FIELD_VALUE] - - // Actuator target (only used if the entry is an actuator) - Datapoint actuator_target = 3; // [field: FIELD_ACTUATOR_TARGET] - - // Metadata for this entry - Metadata metadata = 10; // [field: FIELD_METADATA] -} - -message Datapoint { - google.protobuf.Timestamp timestamp = 1; - - oneof value { - string string = 11; - bool bool = 12; - sint32 int32 = 13; - sint64 int64 = 14; - uint32 uint32 = 15; - uint64 uint64 = 16; - float float = 17; - double double = 18; - StringArray string_array = 21; - BoolArray bool_array = 22; - Int32Array int32_array = 23; - Int64Array int64_array = 24; - Uint32Array uint32_array = 25; - Uint64Array uint64_array = 26; - FloatArray float_array = 27; - DoubleArray double_array = 28; - } -} - -message Metadata { - // Data type - // The VSS data type of the entry (i.e. the value, min, max etc). - // - // NOTE: protobuf doesn't have int8, int16, uint8 or uint16 which means - // that these values must be serialized as int32 and uint32 respectively. - DataType data_type = 11; // [field: FIELD_METADATA_DATA_TYPE] - - // Entry type - EntryType entry_type = 12; // [field: FIELD_METADATA_ENTRY_TYPE] - - // Description - // Describes the meaning and content of the entry. - optional string description = 13; // [field: FIELD_METADATA_DESCRIPTION] - - // Comment [optional] - // A comment can be used to provide additional informal information - // on a entry. - optional string comment = 14; // [field: FIELD_METADATA_COMMENT] - - // Deprecation [optional] - // Whether this entry is deprecated. Can contain recommendations of what - // to use instead. - optional string deprecation = 15; // [field: FIELD_METADATA_DEPRECATION] - - // Unit [optional] - // The unit of measurement - optional string unit = 16; // [field: FIELD_METADATA_UNIT] - - // Value restrictions [optional] - // Restrict which values are allowed. - // Only restrictions matching the DataType {datatype} above are valid. - ValueRestriction value_restriction = 17; // [field: FIELD_METADATA_VALUE_RESTRICTION] - - // Entry type specific metadata - oneof entry_specific { - Actuator actuator = 20; // [field: FIELD_METADATA_ACTUATOR] - Sensor sensor = 30; // [field: FIELD_METADATA_SENSOR] - Attribute attribute = 40; // [field: FIELD_METADATA_ATTRIBUTE] - } -} - -/////////////////////// -// Actuator specific fields -message Actuator { - // Nothing for now -} - -//////////////////////// -// Sensor specific -message Sensor { - // Nothing for now -} - -//////////////////////// -// Attribute specific -message Attribute { - // Nothing for now. -} - -// Value restriction -// -// One ValueRestriction{type} for each type, since -// they don't make sense unless the types match -// -message ValueRestriction { - oneof type { - ValueRestrictionString string = 21; - // For signed VSS integers - ValueRestrictionInt signed = 22; - // For unsigned VSS integers - ValueRestrictionUint unsigned = 23; - // For floating point VSS values (float and double) - ValueRestrictionFloat floating_point = 24; - } -} - -message ValueRestrictionInt { - optional sint64 min = 1; - optional sint64 max = 2; - repeated sint64 allowed_values = 3; -} - -message ValueRestrictionUint { - optional uint64 min = 1; - optional uint64 max = 2; - repeated uint64 allowed_values = 3; -} - -message ValueRestrictionFloat { - optional double min = 1; - optional double max = 2; - - // allowed for doubles/floats not recommended - repeated double allowed_values = 3; -} - -// min, max doesn't make much sense for a string -message ValueRestrictionString { - repeated string allowed_values = 3; -} - -// VSS Data type of a signal -// -// Protobuf doesn't support int8, int16, uint8 or uint16. -// These are mapped to int32 and uint32 respectively. -// -enum DataType { - DATA_TYPE_UNSPECIFIED = 0; - DATA_TYPE_STRING = 1; - DATA_TYPE_BOOLEAN = 2; - DATA_TYPE_INT8 = 3; - DATA_TYPE_INT16 = 4; - DATA_TYPE_INT32 = 5; - DATA_TYPE_INT64 = 6; - DATA_TYPE_UINT8 = 7; - DATA_TYPE_UINT16 = 8; - DATA_TYPE_UINT32 = 9; - DATA_TYPE_UINT64 = 10; - DATA_TYPE_FLOAT = 11; - DATA_TYPE_DOUBLE = 12; - DATA_TYPE_TIMESTAMP = 13; - DATA_TYPE_STRING_ARRAY = 20; - DATA_TYPE_BOOLEAN_ARRAY = 21; - DATA_TYPE_INT8_ARRAY = 22; - DATA_TYPE_INT16_ARRAY = 23; - DATA_TYPE_INT32_ARRAY = 24; - DATA_TYPE_INT64_ARRAY = 25; - DATA_TYPE_UINT8_ARRAY = 26; - DATA_TYPE_UINT16_ARRAY = 27; - DATA_TYPE_UINT32_ARRAY = 28; - DATA_TYPE_UINT64_ARRAY = 29; - DATA_TYPE_FLOAT_ARRAY = 30; - DATA_TYPE_DOUBLE_ARRAY = 31; - DATA_TYPE_TIMESTAMP_ARRAY = 32; -} - -// Entry type -enum EntryType { - ENTRY_TYPE_UNSPECIFIED = 0; - ENTRY_TYPE_ATTRIBUTE = 1; - ENTRY_TYPE_SENSOR = 2; - ENTRY_TYPE_ACTUATOR = 3; -} - -// A `View` specifies a set of fields which should -// be populated in a `DataEntry` (in a response message) -enum View { - VIEW_UNSPECIFIED = 0; // Unspecified. Equivalent to VIEW_CURRENT_VALUE unless `fields` are explicitly set. - VIEW_CURRENT_VALUE = 1; // Populate DataEntry with value. - VIEW_TARGET_VALUE = 2; // Populate DataEntry with actuator target. - VIEW_METADATA = 3; // Populate DataEntry with metadata. - VIEW_FIELDS = 10; // Populate DataEntry only with requested fields. - VIEW_ALL = 20; // Populate DataEntry with everything. -} - -// A `Field` corresponds to a specific field of a `DataEntry`. -// -// It can be used to: -// * populate only specific fields of a `DataEntry` response. -// * specify which fields of a `DataEntry` should be set as -// part of a `Set` request. -// * subscribe to only specific fields of a data entry. -// * convey which fields of an updated `DataEntry` have changed. -enum Field { - FIELD_UNSPECIFIED = 0; // "*" i.e. everything - FIELD_PATH = 1; // path - FIELD_VALUE = 2; // value - FIELD_ACTUATOR_TARGET = 3; // actuator_target - FIELD_METADATA = 10; // metadata.* - FIELD_METADATA_DATA_TYPE = 11; // metadata.data_type - FIELD_METADATA_DESCRIPTION = 12; // metadata.description - FIELD_METADATA_ENTRY_TYPE = 13; // metadata.entry_type - FIELD_METADATA_COMMENT = 14; // metadata.comment - FIELD_METADATA_DEPRECATION = 15; // metadata.deprecation - FIELD_METADATA_UNIT = 16; // metadata.unit - FIELD_METADATA_VALUE_RESTRICTION = 17; // metadata.value_restriction.* - FIELD_METADATA_ACTUATOR = 20; // metadata.actuator.* - FIELD_METADATA_SENSOR = 30; // metadata.sensor.* - FIELD_METADATA_ATTRIBUTE = 40; // metadata.attribute.* -} - -// Error response shall be an HTTP-like code. -// Should follow https://www.w3.org/TR/viss2-transport/#status-codes. -message Error { - uint32 code = 1; - string reason = 2; - string message = 3; -} - -// Used in get/set requests to report errors for specific entries -message DataEntryError { - string path = 1; // vss path - Error error = 2; -} - -message StringArray { - repeated string values = 1; -} - -message BoolArray { - repeated bool values = 1; -} - -message Int32Array { - repeated sint32 values = 1; -} - -message Int64Array { - repeated sint64 values = 1; -} - -message Uint32Array { - repeated uint32 values = 1; -} - -message Uint64Array { - repeated uint64 values = 1; -} - -message FloatArray { - repeated float values = 1; -} - -message DoubleArray { - repeated double values = 1; -} diff --git a/proto/kuksa/val/v1/val.proto b/proto/kuksa/val/v1/val.proto deleted file mode 100644 index 3059d8098..000000000 --- a/proto/kuksa/val/v1/val.proto +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License 2.0 which is available at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -syntax = "proto3"; - -package kuksa.val.v1; - -option go_package = "kuksa/val/v1"; - -import "kuksa/val/v1/types.proto"; - -// Note on authorization: -// Tokens (auth-token or auth-uuid) are sent as (GRPC / http2) metadata. -// -// The auth-token is a JWT compliant token as the examples found here: -// https://github.com/eclipse/kuksa.val/tree/master/kuksa_certificates/jwt -// -// See also https://github.com/eclipse/kuksa.val/blob/master/doc/jwt.md -// -// Upon reception of auth-token, server shall generate an auth-uuid in metadata -// that the client can use instead of auth-token in subsequent calls. - -service VAL { - // Get entries - rpc Get(GetRequest) returns (GetResponse); - - // Set entries - rpc Set(SetRequest) returns (SetResponse); - - // Subscribe to a set of entries - // - // Returns a stream of notifications. - // - // InvalidArgument is returned if the request is malformed. - rpc Subscribe(SubscribeRequest) returns (stream SubscribeResponse); - - // Shall return information that allows the client to determine - // what server/server implementation/version it is talking to - // eg. kuksa-databroker 0.5.1 - rpc GetServerInfo(GetServerInfoRequest) returns (GetServerInfoResponse); -} - -// Define which data we want -message EntryRequest { - string path = 1; - View view = 2; - repeated Field fields = 3; -} - -// Request a set of entries. -message GetRequest { - repeated EntryRequest entries = 1; -} - -// Global errors are specified in `error`. -// Errors for individual entries are specified in `errors`. -message GetResponse { - repeated DataEntry entries = 1; - repeated DataEntryError errors = 2; - Error error = 3; -} - -// Define the data we want to set -message EntryUpdate { - DataEntry entry = 1; - repeated Field fields = 2; -} - -// A list of entries to be updated -message SetRequest { - repeated EntryUpdate updates = 1; -} - -// Global errors are specified in `error`. -// Errors for individual entries are specified in `errors`. -message SetResponse { - Error error = 1; - repeated DataEntryError errors = 2; -} - -// Define what to subscribe to -message SubscribeEntry { - string path = 1; - View view = 2; - repeated Field fields = 3; -} - -// Subscribe to changes in datapoints. -message SubscribeRequest { - repeated SubscribeEntry entries = 1; -} - -// A subscription response -message SubscribeResponse { - repeated EntryUpdate updates = 1; -} - -message GetServerInfoRequest { - // Nothing yet -} - -message GetServerInfoResponse { - string name = 1; - string version = 2; -} \ No newline at end of file