mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-04-17 20:50:14 +00:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
927a68a436 | |||
417179ba54 | |||
1813e6a7b2 | |||
e2682db6e2 | |||
aa9923a60b | |||
fd061d4657 | |||
e3fae6260b | |||
07d4e89a92 | |||
8e7f321e93 |
Cargo.lock
api
backend
chirpstack
lrwn
ui
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -672,7 +672,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "backend"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
dependencies = [
|
||||
"aes-kw",
|
||||
"anyhow",
|
||||
@ -889,7 +889,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chirpstack"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"anyhow",
|
||||
@ -968,7 +968,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chirpstack_api"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"pbjson",
|
||||
@ -2207,7 +2207,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lrwn"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"anyhow",
|
||||
|
2
api/grpc-web/package.json
vendored
2
api/grpc-web/package.json
vendored
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@chirpstack/chirpstack-api-grpc-web",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.3",
|
||||
"description": "Chirpstack gRPC-web API",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
|
14
api/js/package.json
vendored
14
api/js/package.json
vendored
@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@chirpstack/chirpstack-api",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.3",
|
||||
"description": "Chirpstack JS and TS API",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"grpc-tools": "^1.11.2",
|
||||
"grpc-tools": "^1.12.3",
|
||||
"ts-protoc-gen": "^0.15.0",
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.3.7",
|
||||
"@mapbox/node-pre-gyp": "^1.0.5",
|
||||
"@types/google-protobuf": "^3.15.5",
|
||||
"google-protobuf": "^3.17.3"
|
||||
"@grpc/grpc-js": "^1.8.0",
|
||||
"@mapbox/node-pre-gyp": "^1.0.10",
|
||||
"@types/google-protobuf": "^3.15.6",
|
||||
"google-protobuf": "^3.21.2"
|
||||
}
|
||||
}
|
||||
|
82
api/js/yarn.lock
vendored
82
api/js/yarn.lock
vendored
@ -2,25 +2,40 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@grpc/grpc-js@^1.3.7":
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.2.tgz#fbaceefd163f4886e39501aea32a19c0fe802232"
|
||||
integrity sha512-9+89Ne1K8F9u86T+l1yIV2DS+dWHYVK61SsDZN4MFTFehOOaJ4rHxa1cW8Lwdn2/6tOx7N3+SY/vfcjztOHopA==
|
||||
"@grpc/grpc-js@^1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.0.tgz#ebfbeff2b76e2991f2831e46cad27fa573396555"
|
||||
integrity sha512-ySMTXQuMvvswoobvN+0LsaPf7ITO2JVfJmHxQKI4cGehNrrUms+n81BlHEX7Hl/LExji6XE3fnI9U04GSkRruA==
|
||||
dependencies:
|
||||
"@grpc/proto-loader" "^0.6.4"
|
||||
"@grpc/proto-loader" "^0.7.0"
|
||||
"@types/node" ">=12.12.47"
|
||||
|
||||
"@grpc/proto-loader@^0.6.4":
|
||||
version "0.6.9"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.9.tgz#4014eef366da733f8e04a9ddd7376fe8a58547b7"
|
||||
integrity sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg==
|
||||
"@grpc/proto-loader@^0.7.0":
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.4.tgz#4946a84fbf47c3ddd4e6a97acb79d69a9f47ebf2"
|
||||
integrity sha512-MnWjkGwqQ3W8fx94/c1CwqLsNmHHv2t0CFn+9++6+cDphC1lolpg9M2OU0iebIjK//pBNX9e94ho+gjx6vz39w==
|
||||
dependencies:
|
||||
"@types/long" "^4.0.1"
|
||||
lodash.camelcase "^4.3.0"
|
||||
long "^4.0.0"
|
||||
protobufjs "^6.10.0"
|
||||
protobufjs "^7.0.0"
|
||||
yargs "^16.2.0"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.10":
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
|
||||
integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
|
||||
dependencies:
|
||||
detect-libc "^2.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
make-dir "^3.1.0"
|
||||
node-fetch "^2.6.7"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^5.0.1"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.5":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
|
||||
@ -89,10 +104,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@types/google-protobuf@^3.15.5":
|
||||
version "3.15.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.5.tgz#644b2be0f5613b1f822c70c73c6b0e0b5b5fa2ad"
|
||||
integrity sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==
|
||||
"@types/google-protobuf@^3.15.6":
|
||||
version "3.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz#674a69493ef2c849b95eafe69167ea59079eb504"
|
||||
integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.2"
|
||||
@ -266,15 +281,20 @@ glob@^7.1.3:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
google-protobuf@^3.15.5, google-protobuf@^3.17.3:
|
||||
google-protobuf@^3.15.5:
|
||||
version "3.20.0"
|
||||
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.20.0.tgz#8705ab5fb7e91e9578250a4a8ac533a3cc0bc0bb"
|
||||
integrity sha512-hhXv5IKLDIkb0pEm53G053UZGhRAhw3wM5Jk7ly5sGIQRkO1s63FaDqM9QjlrPHygKEE2awUlLP9fFrG6M9vfQ==
|
||||
|
||||
grpc-tools@^1.11.2:
|
||||
version "1.11.2"
|
||||
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.11.2.tgz#22d802d40012510ccc6591d11f9c94109ac07aab"
|
||||
integrity sha512-4+EgpnnkJraamY++oyBCw5Hp9huRYfgakjNVKbiE3PgO9Tv5ydVlRo7ZyGJ0C0SEiA7HhbVc1sNNtIyK7FiEtg==
|
||||
google-protobuf@^3.21.2:
|
||||
version "3.21.2"
|
||||
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
|
||||
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
|
||||
|
||||
grpc-tools@^1.12.3:
|
||||
version "1.12.3"
|
||||
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.3.tgz#bedbb880e564a52b192d693300280ed7ab45e61d"
|
||||
integrity sha512-KJgk65dbGqkMuj0xiuT5uk45GcqrFfWTSqpk6Ktd0Ds2cEe9QtPQG/uWCGk185ShXCdgYFLRwfh+FyjQ3nlBNw==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||
|
||||
@ -319,6 +339,11 @@ long@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
|
||||
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
|
||||
|
||||
long@^5.0.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f"
|
||||
integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
@ -406,10 +431,10 @@ path-is-absolute@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
protobufjs@^6.10.0:
|
||||
version "6.11.3"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
|
||||
integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
|
||||
protobufjs@^7.0.0:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c"
|
||||
integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@ -421,9 +446,8 @@ protobufjs@^6.10.0:
|
||||
"@protobufjs/path" "^1.1.2"
|
||||
"@protobufjs/pool" "^1.1.0"
|
||||
"@protobufjs/utf8" "^1.1.0"
|
||||
"@types/long" "^4.0.1"
|
||||
"@types/node" ">=13.7.0"
|
||||
long "^4.0.0"
|
||||
long "^5.0.0"
|
||||
|
||||
readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
@ -520,10 +544,10 @@ ts-protoc-gen@^0.15.0:
|
||||
dependencies:
|
||||
google-protobuf "^3.15.5"
|
||||
|
||||
typescript@^4.3.5:
|
||||
version "4.6.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c"
|
||||
integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==
|
||||
typescript@^4.9.4:
|
||||
version "4.9.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
|
||||
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
|
||||
|
||||
util-deprecate@^1.0.1:
|
||||
version "1.0.2"
|
||||
|
2
api/python/src/setup.py
vendored
2
api/python/src/setup.py
vendored
@ -18,7 +18,7 @@ CLASSIFIERS = [
|
||||
|
||||
setup(
|
||||
name='chirpstack-api',
|
||||
version = "4.1.0",
|
||||
version = "4.1.3",
|
||||
url='https://github.com/brocaar/chirpstack-api',
|
||||
author='Orne Brocaar',
|
||||
author_email='info@brocaar.com',
|
||||
|
2
api/rust/Cargo.lock
generated
vendored
2
api/rust/Cargo.lock
generated
vendored
@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chirpstack_api"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"pbjson",
|
||||
|
2
api/rust/Cargo.toml
vendored
2
api/rust/Cargo.toml
vendored
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "chirpstack_api"
|
||||
description = "ChirpStack Protobuf / gRPC API definitions."
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://www.chirpstack.io"
|
||||
|
62
api/rust/build.rs
vendored
62
api/rust/build.rs
vendored
@ -7,6 +7,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let proto_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let proto_dir = Path::new(&proto_dir);
|
||||
let proto_dir = proto_dir.join("proto");
|
||||
let cs_dir = proto_dir.join("chirpstack");
|
||||
|
||||
std::fs::create_dir_all(out_dir.join("common")).unwrap();
|
||||
std::fs::create_dir_all(out_dir.join("gw")).unwrap();
|
||||
@ -22,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.compile_well_known_types(true)
|
||||
.extern_path(".google.protobuf", "::pbjson_types")
|
||||
.compile(
|
||||
&["common/common.proto"],
|
||||
&[cs_dir.join("common").join("common.proto").to_str().unwrap()],
|
||||
&[
|
||||
proto_dir.join("chirpstack").to_str().unwrap(),
|
||||
proto_dir.join("google").to_str().unwrap(),
|
||||
@ -43,7 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.extern_path(".google.protobuf", "::pbjson_types")
|
||||
.extern_path(".common", "crate::common")
|
||||
.compile(
|
||||
&["gw/gw.proto"],
|
||||
&[cs_dir.join("gw").join("gw.proto").to_str().unwrap()],
|
||||
&[
|
||||
proto_dir.join("chirpstack").to_str().unwrap(),
|
||||
proto_dir.join("google").to_str().unwrap(),
|
||||
@ -65,7 +66,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.extern_path(".google.protobuf", "::pbjson_types")
|
||||
.extern_path(".common", "crate::common")
|
||||
.compile(
|
||||
&["internal/internal.proto"],
|
||||
&[cs_dir
|
||||
.join("internal")
|
||||
.join("internal.proto")
|
||||
.to_str()
|
||||
.unwrap()],
|
||||
&[
|
||||
proto_dir.join("chirpstack").to_str().unwrap(),
|
||||
proto_dir.join("google").to_str().unwrap(),
|
||||
@ -88,7 +93,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.extern_path(".common", "crate::common")
|
||||
.extern_path(".gw", "crate::gw")
|
||||
.compile(
|
||||
&["integration/integration.proto"],
|
||||
&[cs_dir
|
||||
.join("integration")
|
||||
.join("integration.proto")
|
||||
.to_str()
|
||||
.unwrap()],
|
||||
&[
|
||||
proto_dir.join("chirpstack").to_str().unwrap(),
|
||||
proto_dir.join("google").to_str().unwrap(),
|
||||
@ -112,7 +121,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.extern_path(".common", "crate::common")
|
||||
.extern_path(".gw", "crate::gw")
|
||||
.compile(
|
||||
&["meta/meta.proto"],
|
||||
&[cs_dir.join("meta").join("meta.proto").to_str().unwrap()],
|
||||
&[proto_dir.join("chirpstack").to_str().unwrap()],
|
||||
)?;
|
||||
|
||||
@ -132,18 +141,37 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.extern_path(".gw", "crate::gw")
|
||||
.compile(
|
||||
&[
|
||||
"api/internal.proto",
|
||||
"api/user.proto",
|
||||
"api/tenant.proto",
|
||||
"api/application.proto",
|
||||
"api/device_profile.proto",
|
||||
"api/device_profile_template.proto",
|
||||
"api/device.proto",
|
||||
"api/gateway.proto",
|
||||
"api/frame_log.proto",
|
||||
"api/multicast_group.proto",
|
||||
"api/frame_log.proto",
|
||||
"api/request_log.proto",
|
||||
cs_dir.join("api").join("internal.proto").to_str().unwrap(),
|
||||
cs_dir.join("api").join("user.proto").to_str().unwrap(),
|
||||
cs_dir.join("api").join("tenant.proto").to_str().unwrap(),
|
||||
cs_dir
|
||||
.join("api")
|
||||
.join("application.proto")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
cs_dir
|
||||
.join("api")
|
||||
.join("device_profile.proto")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
cs_dir
|
||||
.join("api")
|
||||
.join("device_profile_template.proto")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
cs_dir.join("api").join("device.proto").to_str().unwrap(),
|
||||
cs_dir.join("api").join("gateway.proto").to_str().unwrap(),
|
||||
cs_dir.join("api").join("frame_log.proto").to_str().unwrap(),
|
||||
cs_dir
|
||||
.join("api")
|
||||
.join("multicast_group.proto")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
cs_dir
|
||||
.join("api")
|
||||
.join("request_log.proto")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
],
|
||||
&[
|
||||
proto_dir.join("chirpstack").to_str().unwrap(),
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "backend"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
@ -3,7 +3,7 @@ name = "chirpstack"
|
||||
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
|
||||
repository = "https://github.com/chirpstack/chirpstack"
|
||||
homepage="https://www.chirpstack.io/"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
@ -262,7 +262,7 @@ async fn _handle_pr_start_req_data(
|
||||
let region_name = region::get_region_name(region_common_name)?;
|
||||
let dr = pl.ul_meta_data.data_rate.unwrap_or_default();
|
||||
|
||||
let ufs = UplinkFrameSet {
|
||||
let mut ufs = UplinkFrameSet {
|
||||
uplink_set_id: Uuid::new_v4(),
|
||||
dr,
|
||||
ch: helpers::get_uplink_ch(®ion_name, tx_info.frequency, dr)?,
|
||||
@ -280,7 +280,7 @@ async fn _handle_pr_start_req_data(
|
||||
};
|
||||
|
||||
// get device-session
|
||||
let ds = device_session::get_for_phypayload(&ufs.phy_payload, ufs.dr, ufs.ch as u8).await?;
|
||||
let ds = device_session::get_for_phypayload(&mut ufs.phy_payload, ufs.dr, ufs.ch as u8).await?;
|
||||
let pr_lifetime = roaming::get_passive_roaming_lifetime(sender_id)?;
|
||||
let kek_label = roaming::get_passive_roaming_kek_label(sender_id)?;
|
||||
|
||||
|
@ -333,10 +333,7 @@ impl Data {
|
||||
},
|
||||
};
|
||||
|
||||
integration::ack_event(&self.application.id, &self.device.variables, &pl)
|
||||
.await
|
||||
.context("Publish ack event")?;
|
||||
|
||||
integration::ack_event(self.application.id, &self.device.variables, &pl).await;
|
||||
warn!(dev_eui = %self.device.dev_eui, device_queue_item_id = %qi.id, "Device queue-item discarded because of timeout");
|
||||
|
||||
continue;
|
||||
@ -366,10 +363,7 @@ impl Data {
|
||||
.collect(),
|
||||
};
|
||||
|
||||
integration::log_event(&self.application.id, &self.device.variables, &pl)
|
||||
.await
|
||||
.context("Publish log event")?;
|
||||
|
||||
integration::log_event(self.application.id, &self.device.variables, &pl).await;
|
||||
warn!(dev_eui = %self.device.dev_eui, device_queue_item_id = %qi.id, "Device queue-item discarded because of max. payload size");
|
||||
|
||||
continue;
|
||||
|
@ -318,7 +318,7 @@ impl TxAck {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
integration::log_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::log_event(app.id, &dev.variables, &pl).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -366,7 +366,7 @@ impl TxAck {
|
||||
tx_info: self.downlink_frame_item.as_ref().unwrap().tx_info.clone(),
|
||||
};
|
||||
|
||||
integration::txack_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::txack_event(app.id, &dev.variables, &pl).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -378,7 +378,8 @@ impl Integration {
|
||||
)?)),
|
||||
};
|
||||
|
||||
integration_event(&Uuid::from_str(&di.application_id)?, vars, &int_pl).await
|
||||
integration_event(Uuid::from_str(&di.application_id)?, vars, &int_pl).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_response_downlink(
|
||||
@ -431,7 +432,8 @@ impl Integration {
|
||||
}),
|
||||
};
|
||||
|
||||
location_event(&Uuid::from_str(&di.application_id)?, vars, &loc_pl).await
|
||||
location_event(Uuid::from_str(&di.application_id)?, vars, &loc_pl).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_geoloc_buffer(
|
||||
@ -729,7 +731,7 @@ impl IntegrationTrait for Integration {
|
||||
location: Some(v),
|
||||
};
|
||||
|
||||
location_event(&Uuid::from_str(&di.application_id)?, vars, &loc_pl).await?;
|
||||
location_event(Uuid::from_str(&di.application_id)?, vars, &loc_pl).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -133,7 +133,7 @@ pub trait Integration {
|
||||
}
|
||||
|
||||
// Returns a Vec of integrations for the given Application ID.
|
||||
async fn for_application_id(id: &Uuid) -> Result<Vec<Box<dyn Integration + Sync + Send>>> {
|
||||
async fn for_application_id(id: Uuid) -> Result<Vec<Box<dyn Integration + Sync + Send>>> {
|
||||
#[cfg(test)]
|
||||
{
|
||||
let m = MOCK_INTEGRATION.read().await;
|
||||
@ -143,7 +143,7 @@ async fn for_application_id(id: &Uuid) -> Result<Vec<Box<dyn Integration + Sync
|
||||
}
|
||||
|
||||
let mut out: Vec<Box<dyn Integration + Sync + Send>> = Vec::new();
|
||||
let integrations = application::get_integrations_for_application(id).await?;
|
||||
let integrations = application::get_integrations_for_application(&id).await?;
|
||||
|
||||
for app_i in &integrations {
|
||||
out.push(match &app_i.configuration {
|
||||
@ -187,7 +187,24 @@ async fn for_application_id(id: &Uuid) -> Result<Vec<Box<dyn Integration + Sync
|
||||
}
|
||||
|
||||
pub async fn uplink_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::UplinkEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _uplink_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Uplink event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _uplink_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::UplinkEvent,
|
||||
) -> Result<()> {
|
||||
@ -212,7 +229,24 @@ pub async fn uplink_event(
|
||||
}
|
||||
|
||||
pub async fn join_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::JoinEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _join_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Join event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _join_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::JoinEvent,
|
||||
) -> Result<()> {
|
||||
@ -237,7 +271,24 @@ pub async fn join_event(
|
||||
}
|
||||
|
||||
pub async fn ack_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::AckEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _ack_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Ack event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _ack_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::AckEvent,
|
||||
) -> Result<()> {
|
||||
@ -262,7 +313,24 @@ pub async fn ack_event(
|
||||
}
|
||||
|
||||
pub async fn txack_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::TxAckEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _txack_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Txack event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _txack_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::TxAckEvent,
|
||||
) -> Result<()> {
|
||||
@ -287,7 +355,24 @@ pub async fn txack_event(
|
||||
}
|
||||
|
||||
pub async fn log_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::LogEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _log_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Log event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _log_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::LogEvent,
|
||||
) -> Result<()> {
|
||||
@ -312,7 +397,24 @@ pub async fn log_event(
|
||||
}
|
||||
|
||||
pub async fn status_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::StatusEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _status_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Status event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _status_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::StatusEvent,
|
||||
) -> Result<()> {
|
||||
@ -337,7 +439,24 @@ pub async fn status_event(
|
||||
}
|
||||
|
||||
pub async fn location_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::LocationEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _location_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Location event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _location_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::LocationEvent,
|
||||
) -> Result<()> {
|
||||
@ -362,7 +481,24 @@ pub async fn location_event(
|
||||
}
|
||||
|
||||
pub async fn integration_event(
|
||||
application_id: &Uuid,
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::IntegrationEvent,
|
||||
) {
|
||||
tokio::spawn({
|
||||
let vars = vars.clone();
|
||||
let pl = pl.clone();
|
||||
|
||||
async move {
|
||||
if let Err(err) = _integration_event(application_id, &vars, &pl).await {
|
||||
error!(application_id = %application_id, error = %err, "Location event error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn _integration_event(
|
||||
application_id: Uuid,
|
||||
vars: &HashMap<String, String>,
|
||||
pl: &integration::IntegrationEvent,
|
||||
) -> Result<()> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use bigdecimal::BigDecimal;
|
||||
use chrono::{DateTime, Utc};
|
||||
use tracing::{error, info};
|
||||
use tracing::info;
|
||||
|
||||
use crate::integration;
|
||||
use crate::storage::{application, device, device_profile, tenant};
|
||||
@ -48,8 +48,8 @@ pub async fn handle(
|
||||
let rx_time: DateTime<Utc> =
|
||||
helpers::get_rx_timestamp(&uplink_frame_set.rx_info_set).into();
|
||||
|
||||
if let Err(e) = integration::status_event(
|
||||
&app.id,
|
||||
integration::status_event(
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::StatusEvent {
|
||||
deduplication_id: uplink_frame_set.uplink_set_id.to_string(),
|
||||
@ -75,10 +75,7 @@ pub async fn handle(
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!(error = %e, "Sending status event error");
|
||||
}
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
@ -94,6 +91,8 @@ pub mod test {
|
||||
use lrwn::EUI64;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[test]
|
||||
@ -189,6 +188,9 @@ pub mod test {
|
||||
.unwrap();
|
||||
assert_eq!(true, resp.is_none());
|
||||
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let status_events = mock::get_status_events().await;
|
||||
assert_eq!(
|
||||
vec![integration_pb::StatusEvent {
|
||||
|
@ -122,15 +122,13 @@ pub async fn delete(dev_eui: &EUI64) -> Result<()> {
|
||||
// This function will increment the uplink frame-counter and will immediately update the
|
||||
// device-session in the database, to make sure that in case this function is called multiple
|
||||
// times, at most one will be valid.
|
||||
// On Ok response, the PhyPayload f_cnt will be set to the full 32bit frame-counter based on the
|
||||
// device-session context.
|
||||
pub async fn get_for_phypayload_and_incr_f_cnt_up(
|
||||
phy: &PhyPayload,
|
||||
phy: &mut PhyPayload,
|
||||
tx_dr: u8,
|
||||
tx_ch: u8,
|
||||
) -> Result<ValidationStatus, Error> {
|
||||
// Clone the PhyPayload, as we will update the f_cnt to the full (32bit) frame-counter value
|
||||
// for calculating the MIC.
|
||||
let mut phy = phy.clone();
|
||||
|
||||
let mut _dev_addr = DevAddr::from_be_bytes([0x00, 0x00, 0x00, 0x00]);
|
||||
let mut _f_cnt_orig = 0;
|
||||
|
||||
@ -150,11 +148,6 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
|
||||
}
|
||||
|
||||
for mut ds in device_sessions {
|
||||
// Restore the original f_cnt.
|
||||
if let Payload::MACPayload(pl) = &mut phy.payload {
|
||||
pl.fhdr.f_cnt = _f_cnt_orig;
|
||||
}
|
||||
|
||||
// Get the full 32bit frame-counter.
|
||||
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, _f_cnt_orig);
|
||||
let f_nwk_s_int_key = AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
|
||||
@ -236,6 +229,11 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
|
||||
return Ok(ValidationStatus::Reset(full_f_cnt, ds));
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the original f_cnt.
|
||||
if let Payload::MACPayload(pl) = &mut phy.payload {
|
||||
pl.fhdr.f_cnt = _f_cnt_orig;
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::InvalidMIC)
|
||||
@ -244,15 +242,13 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
|
||||
// Simmilar to get_for_phypayload_and_incr_f_cnt_up, but only retrieves the device-session for the
|
||||
// given PhyPayload. As it does not return the ValidationStatus, it only returns the DeviceSession
|
||||
// in case of a valid frame-counter.
|
||||
// On Ok response, the PhyPayload f_cnt will be set to the full 32bit frame-counter based on the
|
||||
// device-session context.
|
||||
pub async fn get_for_phypayload(
|
||||
phy: &PhyPayload,
|
||||
phy: &mut PhyPayload,
|
||||
tx_dr: u8,
|
||||
tx_ch: u8,
|
||||
) -> Result<internal::DeviceSession, Error> {
|
||||
// Clone the PhyPayload, as we will update the f_cnt to the full (32bit) frame-counter value
|
||||
// for calculating the MIC.
|
||||
let mut phy = phy.clone();
|
||||
|
||||
// Get the dev_addr and original f_cnt.
|
||||
let (dev_addr, f_cnt_orig) = if let Payload::MACPayload(pl) = &phy.payload {
|
||||
(pl.fhdr.devaddr, pl.fhdr.f_cnt)
|
||||
@ -268,11 +264,6 @@ pub async fn get_for_phypayload(
|
||||
}
|
||||
|
||||
for ds in device_sessions {
|
||||
// Restore the original f_cnt.
|
||||
if let Payload::MACPayload(pl) = &mut phy.payload {
|
||||
pl.fhdr.f_cnt = f_cnt_orig;
|
||||
}
|
||||
|
||||
// Get the full 32bit frame-counter.
|
||||
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, f_cnt_orig);
|
||||
let f_nwk_s_int_key = AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
|
||||
@ -297,6 +288,11 @@ pub async fn get_for_phypayload(
|
||||
if mic_ok && full_f_cnt >= ds.f_cnt_up {
|
||||
return Ok(ds);
|
||||
}
|
||||
|
||||
// Restore the original f_cnt.
|
||||
if let Payload::MACPayload(pl) = &mut phy.payload {
|
||||
pl.fhdr.f_cnt = f_cnt_orig;
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::InvalidMIC)
|
||||
@ -511,6 +507,24 @@ pub mod test {
|
||||
})),
|
||||
..Default::default()
|
||||
},
|
||||
internal::DeviceSession {
|
||||
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
|
||||
dev_eui: vec![0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05],
|
||||
s_nwk_s_int_key: vec![
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05,
|
||||
],
|
||||
f_nwk_s_int_key: vec![
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05,
|
||||
],
|
||||
nwk_s_enc_key: vec![
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05,
|
||||
],
|
||||
f_cnt_up: (1 << 16) + 1,
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
|
||||
for ds in &device_sessions {
|
||||
@ -628,6 +642,24 @@ pub mod test {
|
||||
expected_error: None,
|
||||
expected_reset: false,
|
||||
},
|
||||
Test {
|
||||
name: "frame-counter rollover (16lsb)".to_string(),
|
||||
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
|
||||
f_nwk_s_int_key: AES128Key::from_bytes([
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05,
|
||||
]),
|
||||
s_nwk_s_int_key: AES128Key::from_bytes([
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05,
|
||||
]),
|
||||
f_cnt: (1 << 16) + 11,
|
||||
expected_dev_eui: EUI64::from_slice(&device_sessions[3].dev_eui).unwrap(),
|
||||
expected_fcnt_up: (1 << 16) + 11,
|
||||
expected_retransmission: false,
|
||||
expected_error: None,
|
||||
expected_reset: false,
|
||||
},
|
||||
];
|
||||
|
||||
for tst in &tests {
|
||||
@ -658,15 +690,29 @@ pub mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ds_res = get_for_phypayload_and_incr_f_cnt_up(&phy, 0, 0).await;
|
||||
// Truncate to 16LSB (as it would be transmitted over the air).
|
||||
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
|
||||
pl.fhdr.f_cnt = tst.f_cnt % (1 << 16);
|
||||
}
|
||||
|
||||
let ds_res = get_for_phypayload_and_incr_f_cnt_up(&mut phy, 0, 0).await;
|
||||
if tst.expected_error.is_some() {
|
||||
assert_eq!(true, ds_res.is_err());
|
||||
assert_eq!(
|
||||
tst.expected_error.as_ref().unwrap(),
|
||||
&ds_res.err().unwrap().to_string()
|
||||
);
|
||||
if let lrwn::Payload::MACPayload(pl) = &phy.payload {
|
||||
assert_eq!(tst.f_cnt, pl.fhdr.f_cnt);
|
||||
}
|
||||
} else {
|
||||
let ds = ds_res.unwrap();
|
||||
|
||||
// Validate that the f_cnt of the PhyPayload was set to the full frame-counter.
|
||||
if let lrwn::Payload::MACPayload(pl) = &phy.payload {
|
||||
assert_eq!(tst.expected_fcnt_up, pl.fhdr.f_cnt);
|
||||
}
|
||||
|
||||
if let ValidationStatus::Ok(full_f_cnt, ds) = ds {
|
||||
assert_eq!(false, tst.expected_retransmission);
|
||||
assert_eq!(
|
||||
|
@ -38,6 +38,7 @@ pub type PgPoolConnection = PooledConnection<ConnectionManager<PgConnection>>;
|
||||
lazy_static! {
|
||||
static ref PG_POOL: RwLock<Option<PgPool>> = RwLock::new(None);
|
||||
static ref REDIS_POOL: RwLock<Option<RedisPool>> = RwLock::new(None);
|
||||
static ref REDIS_PREFIX: RwLock<String> = RwLock::new("".to_string());
|
||||
}
|
||||
|
||||
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations");
|
||||
@ -210,6 +211,11 @@ pub async fn setup() -> Result<()> {
|
||||
set_redis_pool(RedisPool::Client(pool));
|
||||
}
|
||||
|
||||
if !conf.redis.key_prefix.is_empty() {
|
||||
info!(prefix = %conf.redis.key_prefix, "Setting Redis prefix");
|
||||
*REDIS_PREFIX.write().unwrap() = conf.redis.key_prefix.clone();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -244,7 +250,8 @@ pub fn set_redis_pool(p: RedisPool) {
|
||||
}
|
||||
|
||||
pub fn redis_key(s: String) -> String {
|
||||
s
|
||||
let prefix = REDIS_PREFIX.read().unwrap();
|
||||
format!("{}{}", prefix, s)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -264,3 +271,23 @@ pub async fn reset_redis() -> Result<()> {
|
||||
redis::cmd("FLUSHALL").query(&mut *c)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_prefix_no_prefix() {
|
||||
*REDIS_PREFIX.write().unwrap() = "".to_string();
|
||||
assert_eq!("lora:test:key", redis_key("lora:test:key".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prefix() {
|
||||
*REDIS_PREFIX.write().unwrap() = "foobar:".to_string();
|
||||
assert_eq!(
|
||||
"foobar:lora:test:key",
|
||||
redis_key("lora:test:key".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
use std::future::Future;
|
||||
use std::io::Cursor;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
|
||||
use prost::Message;
|
||||
use redis::streams::StreamReadReply;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::gateway::backend::mock as gateway_mock;
|
||||
use crate::integration::mock;
|
||||
@ -122,6 +124,9 @@ pub fn integration_log(logs: Vec<String>) -> Validator {
|
||||
Box::new(move || {
|
||||
let logs = logs.clone();
|
||||
Box::pin(async move {
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mock_logs = mock::get_log_events().await;
|
||||
assert_eq!(logs.len(), mock_logs.len());
|
||||
|
||||
@ -136,6 +141,9 @@ pub fn integration_log(logs: Vec<String>) -> Validator {
|
||||
pub fn no_uplink_event() -> Validator {
|
||||
Box::new(move || {
|
||||
Box::pin(async move {
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mock_events = mock::get_uplink_events().await;
|
||||
assert_eq!(0, mock_events.len());
|
||||
})
|
||||
@ -146,6 +154,9 @@ pub fn uplink_event(up: integration_pb::UplinkEvent) -> Validator {
|
||||
Box::new(move || {
|
||||
let up = up.clone();
|
||||
Box::pin(async move {
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mut mock_events = mock::get_uplink_events().await;
|
||||
assert_eq!(1, mock_events.len());
|
||||
|
||||
@ -163,6 +174,9 @@ pub fn ack_event(ack: integration_pb::AckEvent) -> Validator {
|
||||
Box::new(move || {
|
||||
let ack = ack.clone();
|
||||
Box::pin(async move {
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mut mock_events = mock::get_ack_events().await;
|
||||
assert_eq!(1, mock_events.len());
|
||||
|
||||
@ -180,6 +194,9 @@ pub fn status_event(st: integration_pb::StatusEvent) -> Validator {
|
||||
Box::new(move || {
|
||||
let st = st.clone();
|
||||
Box::pin(async move {
|
||||
// Integration events are handled async.
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mut mock_events = mock::get_status_events().await;
|
||||
assert_eq!(1, mock_events.len());
|
||||
|
||||
|
@ -132,53 +132,58 @@ impl Data {
|
||||
async fn get_device_session(&mut self) -> Result<(), Error> {
|
||||
trace!("Getting device-session for dev_addr");
|
||||
|
||||
if let lrwn::Payload::MACPayload(pl) = &self.uplink_frame_set.phy_payload.payload {
|
||||
match device_session::get_for_phypayload_and_incr_f_cnt_up(
|
||||
&self.uplink_frame_set.phy_payload,
|
||||
self.uplink_frame_set.dr,
|
||||
self.uplink_frame_set.ch as u8,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(v) => match v {
|
||||
device_session::ValidationStatus::Ok(f_cnt, ds) => {
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
device_session::ValidationStatus::Retransmission(f_cnt, ds) => {
|
||||
self.retransmission = true;
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
device_session::ValidationStatus::Reset(f_cnt, ds) => {
|
||||
self.reset = true;
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
},
|
||||
Err(e) => match e {
|
||||
StorageError::NotFound(s) => {
|
||||
warn!(dev_addr = %s, "No device-session exists for dev_addr");
|
||||
return Err(Error::Abort);
|
||||
}
|
||||
StorageError::InvalidMIC => {
|
||||
warn!(dev_addr = %pl.fhdr.devaddr, "None of the device-sessions for dev_addr resulted in valid MIC");
|
||||
|
||||
// Log uplink for null DevEUI.
|
||||
let mut ufl: api::UplinkFrameLog = (&self.uplink_frame_set).try_into()?;
|
||||
ufl.dev_eui = "0000000000000000".to_string();
|
||||
framelog::log_uplink_for_device(&ufl).await?;
|
||||
|
||||
return Err(Error::Abort);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::AnyhowError(
|
||||
anyhow::Error::new(e).context("Get device-session"),
|
||||
));
|
||||
}
|
||||
},
|
||||
let dev_addr =
|
||||
if let lrwn::Payload::MACPayload(pl) = &self.uplink_frame_set.phy_payload.payload {
|
||||
pl.fhdr.devaddr
|
||||
} else {
|
||||
return Err(Error::AnyhowError(anyhow!("No MacPayload in PhyPayload")));
|
||||
};
|
||||
}
|
||||
|
||||
match device_session::get_for_phypayload_and_incr_f_cnt_up(
|
||||
&mut self.uplink_frame_set.phy_payload,
|
||||
self.uplink_frame_set.dr,
|
||||
self.uplink_frame_set.ch as u8,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(v) => match v {
|
||||
device_session::ValidationStatus::Ok(f_cnt, ds) => {
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
device_session::ValidationStatus::Retransmission(f_cnt, ds) => {
|
||||
self.retransmission = true;
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
device_session::ValidationStatus::Reset(f_cnt, ds) => {
|
||||
self.reset = true;
|
||||
self.device_session = Some(ds);
|
||||
self.f_cnt_up_full = f_cnt;
|
||||
}
|
||||
},
|
||||
Err(e) => match e {
|
||||
StorageError::NotFound(s) => {
|
||||
warn!(dev_addr = %s, "No device-session exists for dev_addr");
|
||||
return Err(Error::Abort);
|
||||
}
|
||||
StorageError::InvalidMIC => {
|
||||
warn!(dev_addr = %dev_addr, "None of the device-sessions for dev_addr resulted in valid MIC");
|
||||
|
||||
// Log uplink for null DevEUI.
|
||||
let mut ufl: api::UplinkFrameLog = (&self.uplink_frame_set).try_into()?;
|
||||
ufl.dev_eui = "0000000000000000".to_string();
|
||||
framelog::log_uplink_for_device(&ufl).await?;
|
||||
|
||||
return Err(Error::Abort);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::AnyhowError(
|
||||
anyhow::Error::new(e).context("Get device-session"),
|
||||
));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -310,7 +315,7 @@ impl Data {
|
||||
.cloned()
|
||||
.collect(),
|
||||
};
|
||||
integration::log_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::log_event(app.id, &dev.variables, &pl).await;
|
||||
}
|
||||
|
||||
if self.reset {
|
||||
@ -328,7 +333,7 @@ impl Data {
|
||||
.cloned()
|
||||
.collect(),
|
||||
};
|
||||
integration::log_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::log_event(app.id, &dev.variables, &pl).await;
|
||||
}
|
||||
|
||||
Err(Error::Abort)
|
||||
@ -695,7 +700,7 @@ impl Data {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
time: Some(Utc::now().into()),
|
||||
@ -709,12 +714,12 @@ impl Data {
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
integration::uplink_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::uplink_event(app.id, &dev.variables, &pl).await;
|
||||
|
||||
self.uplink_event = Some(pl);
|
||||
|
||||
@ -866,7 +871,7 @@ impl Data {
|
||||
tags.extend((*dev.tags).clone());
|
||||
|
||||
integration::ack_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::AckEvent {
|
||||
deduplication_id: self.uplink_frame_set.uplink_set_id.to_string(),
|
||||
@ -887,7 +892,7 @@ impl Data {
|
||||
f_cnt_down: qi.f_cnt_down.unwrap_or(0) as u32,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ impl JoinRequest {
|
||||
Err(v) => match v {
|
||||
StorageError::InvalidDevNonce => {
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
time: Some(Utc::now().into()),
|
||||
@ -276,7 +276,7 @@ impl JoinRequest {
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
@ -314,7 +314,7 @@ impl JoinRequest {
|
||||
let dev = self.device.as_ref().unwrap();
|
||||
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
time: Some(Utc::now().into()),
|
||||
@ -331,7 +331,7 @@ impl JoinRequest {
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
@ -739,7 +739,7 @@ impl JoinRequest {
|
||||
dev_addr: self.dev_addr.as_ref().unwrap().to_string(),
|
||||
};
|
||||
|
||||
integration::join_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::join_event(app.id, &dev.variables, &pl).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ impl JoinRequest {
|
||||
Err(v) => match v {
|
||||
StorageError::InvalidDevNonce => {
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
time: Some(Utc::now().into()),
|
||||
@ -318,7 +318,7 @@ impl JoinRequest {
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
@ -356,7 +356,7 @@ impl JoinRequest {
|
||||
let dev = self.device.as_ref().unwrap();
|
||||
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
time: Some(Utc::now().into()),
|
||||
@ -373,7 +373,7 @@ impl JoinRequest {
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
@ -676,7 +676,7 @@ impl JoinRequest {
|
||||
dev_addr: self.dev_addr.as_ref().unwrap().to_string(),
|
||||
};
|
||||
|
||||
integration::join_event(&app.id, &dev.variables, &pl).await?;
|
||||
integration::join_event(app.id, &dev.variables, &pl).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ name = "lrwn"
|
||||
description = "Library for encoding / decoding LoRaWAN frames."
|
||||
homepage = "https://www.chirpstack.io"
|
||||
license = "MIT"
|
||||
version = "4.1.0"
|
||||
version = "4.1.3"
|
||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/chirpstack/chirpstack"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chirpstack-ui",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.3",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
|
@ -1,7 +1,3 @@
|
||||
.ant-notification {
|
||||
z-index: 3000;
|
||||
}
|
||||
|
||||
.layout {
|
||||
margin-left: 300px;
|
||||
}
|
||||
@ -9,7 +5,8 @@
|
||||
.layout-header {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 10px 0px #ccc;
|
||||
z-index: 2000;
|
||||
/* Leaflet JS zoom controls have z-index 1000. */
|
||||
z-index: 1001;
|
||||
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
|
@ -1881,7 +1881,7 @@
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web":
|
||||
version "4.1.0"
|
||||
version "4.1.3"
|
||||
dependencies:
|
||||
"@types/google-protobuf" "^3.15.2"
|
||||
google-protobuf "^3.17.3"
|
||||
|
Reference in New Issue
Block a user