Compare commits

...

12 Commits

Author SHA1 Message Date
411cd681a9 Add cmd to migrate ds from Redis to Pg. 2024-02-22 12:44:14 +00:00
8a986d04ce Fix tests after device-session refactor. 2024-02-21 16:57:03 +00:00
da6b7e1b37 Use Device.device_session field for DS (WIP).
This is work-in-progress, still need to refactor all the tests.
2024-02-21 13:30:08 +00:00
fae182aa3d Migrate code to store device-session in PG (WIP). 2024-02-19 15:27:25 +00:00
5c3624cfbe Work-in-progress test.
This is work-in-progress and only contains a partial implementation.
Downlink (other than OTAA) is not yet implemented. Therefore you should
disable ADR in the region_.toml config when testing.
2024-02-07 15:06:28 +00:00
d599e7a276 Add js context to get_activation api method. 2024-02-06 13:16:26 +00:00
8cde64c4b7 Save metrics in one pipelined Redis query.
This saves the metrics in one pipelined Redis query, rather than one
query per aggregation level. This saves 2 queries per save.
2024-01-31 12:11:54 +00:00
b65faf7b98 Merge deduplication_put and _locked queries.
This merges the deduplication_put and deduplication_locked Redis queries
into a single pipelined query. Simulating 400 uplinks / seconds through
3 gateways (thus 1200 messages / second), and an artificial TCP latency
of 5ms between ChirpStack <> Redis, this reduces the
storage_redis_conn_get_duration_seconds_sum metric by about 50%.

What we are trying to solve here is that under high (simulated) load, we
exhaust the Redis connection pool. This situation gets worse when there
is a significant latency between ChirpStack <> Redis, because the query
takes longer to complete and is reserved from the pool for a longer
time. The result can be that during the de-duplication process, the key
containing the uplink set has already expired before the
deduplicate_collect function is able to get a Redis connection from the
pool.

This query merge is a quick win, because each uplink can be received by
N gateways, thus this merge saves N Redis queries per uplink.
2024-01-31 11:06:03 +00:00
9de86ffdec Track pg and redis get conn metrics.
This data is useful when debugging connection-pool size related issues.
E.g. when more connections are requested than the connection pool allows
then this will result in a longer wait time.
2024-01-31 09:54:00 +00:00
107fbfa7bb Fix setting dev_addr field on ABP activate. 2024-01-25 11:23:33 +00:00
4ce886b21d Bump unsafe-libyaml from 0.2.9 to 0.2.10 (#341)
Bumps [unsafe-libyaml](https://github.com/dtolnay/unsafe-libyaml) from 0.2.9 to 0.2.10.
- [Release notes](https://github.com/dtolnay/unsafe-libyaml/releases)
- [Commits](https://github.com/dtolnay/unsafe-libyaml/compare/0.2.9...0.2.10)

---
updated-dependencies:
- dependency-name: unsafe-libyaml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 15:55:03 +00:00
a1c3431719 Bump follow-redirects from 1.15.3 to 1.15.4 in /ui (#353)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 15:54:33 +00:00
88 changed files with 4604 additions and 3739 deletions

5
Cargo.lock generated
View File

@ -876,6 +876,7 @@ dependencies = [
name = "chirpstack_api" name = "chirpstack_api"
version = "4.7.0-test.3" version = "4.7.0-test.3"
dependencies = [ dependencies = [
"diesel",
"hex", "hex",
"pbjson", "pbjson",
"pbjson-build", "pbjson-build",
@ -4819,9 +4820,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]] [[package]]
name = "unsafe-libyaml" name = "unsafe-libyaml"
version = "0.2.9" version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
[[package]] [[package]]
name = "untrusted" name = "untrusted"

View File

@ -77,99 +77,100 @@ namespace Chirpstack.Api {
"dGVEZXZpY2VSZXF1ZXN0EjAKEWRldmljZV9hY3RpdmF0aW9uGAEgASgLMhUu", "dGVEZXZpY2VSZXF1ZXN0EjAKEWRldmljZV9hY3RpdmF0aW9uGAEgASgLMhUu",
"YXBpLkRldmljZUFjdGl2YXRpb24iKgoXRGVhY3RpdmF0ZURldmljZVJlcXVl", "YXBpLkRldmljZUFjdGl2YXRpb24iKgoXRGVhY3RpdmF0ZURldmljZVJlcXVl",
"c3QSDwoHZGV2X2V1aRgBIAEoCSItChpHZXREZXZpY2VBY3RpdmF0aW9uUmVx", "c3QSDwoHZGV2X2V1aRgBIAEoCSItChpHZXREZXZpY2VBY3RpdmF0aW9uUmVx",
"dWVzdBIPCgdkZXZfZXVpGAEgASgJIk8KG0dldERldmljZUFjdGl2YXRpb25S", "dWVzdBIPCgdkZXZfZXVpGAEgASgJIocBChtHZXREZXZpY2VBY3RpdmF0aW9u",
"ZXNwb25zZRIwChFkZXZpY2VfYWN0aXZhdGlvbhgBIAEoCzIVLmFwaS5EZXZp", "UmVzcG9uc2USMAoRZGV2aWNlX2FjdGl2YXRpb24YASABKAsyFS5hcGkuRGV2",
"Y2VBY3RpdmF0aW9uIioKF0dldFJhbmRvbURldkFkZHJSZXF1ZXN0Eg8KB2Rl", "aWNlQWN0aXZhdGlvbhI2ChNqb2luX3NlcnZlcl9jb250ZXh0GAIgASgLMhku",
"dl9ldWkYASABKAkiLAoYR2V0UmFuZG9tRGV2QWRkclJlc3BvbnNlEhAKCGRl", "Y29tbW9uLkpvaW5TZXJ2ZXJDb250ZXh0IioKF0dldFJhbmRvbURldkFkZHJS",
"dl9hZGRyGAEgASgJIqgBChdHZXREZXZpY2VNZXRyaWNzUmVxdWVzdBIPCgdk", "ZXF1ZXN0Eg8KB2Rldl9ldWkYASABKAkiLAoYR2V0UmFuZG9tRGV2QWRkclJl",
"ZXZfZXVpGAEgASgJEikKBXN0YXJ0GAIgASgLMhouZ29vZ2xlLnByb3RvYnVm", "c3BvbnNlEhAKCGRldl9hZGRyGAEgASgJIqgBChdHZXREZXZpY2VNZXRyaWNz",
"LlRpbWVzdGFtcBInCgNlbmQYAyABKAsyGi5nb29nbGUucHJvdG9idWYuVGlt", "UmVxdWVzdBIPCgdkZXZfZXVpGAEgASgJEikKBXN0YXJ0GAIgASgLMhouZ29v",
"ZXN0YW1wEigKC2FnZ3JlZ2F0aW9uGAQgASgOMhMuY29tbW9uLkFnZ3JlZ2F0", "Z2xlLnByb3RvYnVmLlRpbWVzdGFtcBInCgNlbmQYAyABKAsyGi5nb29nbGUu",
"aW9uIpMCChhHZXREZXZpY2VNZXRyaWNzUmVzcG9uc2USOwoHbWV0cmljcxgB", "cHJvdG9idWYuVGltZXN0YW1wEigKC2FnZ3JlZ2F0aW9uGAQgASgOMhMuY29t",
"IAMoCzIqLmFwaS5HZXREZXZpY2VNZXRyaWNzUmVzcG9uc2UuTWV0cmljc0Vu", "bW9uLkFnZ3JlZ2F0aW9uIpMCChhHZXREZXZpY2VNZXRyaWNzUmVzcG9uc2US",
"dHJ5EjkKBnN0YXRlcxgCIAMoCzIpLmFwaS5HZXREZXZpY2VNZXRyaWNzUmVz", "OwoHbWV0cmljcxgBIAMoCzIqLmFwaS5HZXREZXZpY2VNZXRyaWNzUmVzcG9u",
"cG9uc2UuU3RhdGVzRW50cnkaPgoMTWV0cmljc0VudHJ5EgsKA2tleRgBIAEo", "c2UuTWV0cmljc0VudHJ5EjkKBnN0YXRlcxgCIAMoCzIpLmFwaS5HZXREZXZp",
"CRIdCgV2YWx1ZRgCIAEoCzIOLmNvbW1vbi5NZXRyaWM6AjgBGj8KC1N0YXRl", "Y2VNZXRyaWNzUmVzcG9uc2UuU3RhdGVzRW50cnkaPgoMTWV0cmljc0VudHJ5",
"c0VudHJ5EgsKA2tleRgBIAEoCRIfCgV2YWx1ZRgCIAEoCzIQLmFwaS5EZXZp", "EgsKA2tleRgBIAEoCRIdCgV2YWx1ZRgCIAEoCzIOLmNvbW1vbi5NZXRyaWM6",
"Y2VTdGF0ZToCOAEiKgoLRGV2aWNlU3RhdGUSDAoEbmFtZRgCIAEoCRINCgV2", "AjgBGj8KC1N0YXRlc0VudHJ5EgsKA2tleRgBIAEoCRIfCgV2YWx1ZRgCIAEo",
"YWx1ZRgDIAEoCSKsAQobR2V0RGV2aWNlTGlua01ldHJpY3NSZXF1ZXN0Eg8K", "CzIQLmFwaS5EZXZpY2VTdGF0ZToCOAEiKgoLRGV2aWNlU3RhdGUSDAoEbmFt",
"B2Rldl9ldWkYASABKAkSKQoFc3RhcnQYAiABKAsyGi5nb29nbGUucHJvdG9i", "ZRgCIAEoCRINCgV2YWx1ZRgDIAEoCSKsAQobR2V0RGV2aWNlTGlua01ldHJp",
"dWYuVGltZXN0YW1wEicKA2VuZBgDIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5U", "Y3NSZXF1ZXN0Eg8KB2Rldl9ldWkYASABKAkSKQoFc3RhcnQYAiABKAsyGi5n",
"aW1lc3RhbXASKAoLYWdncmVnYXRpb24YBCABKA4yEy5jb21tb24uQWdncmVn", "b29nbGUucHJvdG9idWYuVGltZXN0YW1wEicKA2VuZBgDIAEoCzIaLmdvb2ds",
"YXRpb24i+wEKHEdldERldmljZUxpbmtNZXRyaWNzUmVzcG9uc2USIgoKcnhf", "ZS5wcm90b2J1Zi5UaW1lc3RhbXASKAoLYWdncmVnYXRpb24YBCABKA4yEy5j",
"cGFja2V0cxgBIAEoCzIOLmNvbW1vbi5NZXRyaWMSHwoHZ3dfcnNzaRgCIAEo", "b21tb24uQWdncmVnYXRpb24i+wEKHEdldERldmljZUxpbmtNZXRyaWNzUmVz",
"CzIOLmNvbW1vbi5NZXRyaWMSHgoGZ3dfc25yGAMgASgLMg4uY29tbW9uLk1l", "cG9uc2USIgoKcnhfcGFja2V0cxgBIAEoCzIOLmNvbW1vbi5NZXRyaWMSHwoH",
"dHJpYxIrChNyeF9wYWNrZXRzX3Blcl9mcmVxGAQgASgLMg4uY29tbW9uLk1l", "Z3dfcnNzaRgCIAEoCzIOLmNvbW1vbi5NZXRyaWMSHgoGZ3dfc25yGAMgASgL",
"dHJpYxIpChFyeF9wYWNrZXRzX3Blcl9kchgFIAEoCzIOLmNvbW1vbi5NZXRy", "Mg4uY29tbW9uLk1ldHJpYxIrChNyeF9wYWNrZXRzX3Blcl9mcmVxGAQgASgL",
"aWMSHgoGZXJyb3JzGAYgASgLMg4uY29tbW9uLk1ldHJpYyLGAQoPRGV2aWNl", "Mg4uY29tbW9uLk1ldHJpYxIpChFyeF9wYWNrZXRzX3Blcl9kchgFIAEoCzIO",
"UXVldWVJdGVtEgoKAmlkGAEgASgJEg8KB2Rldl9ldWkYAiABKAkSEQoJY29u", "LmNvbW1vbi5NZXRyaWMSHgoGZXJyb3JzGAYgASgLMg4uY29tbW9uLk1ldHJp",
"ZmlybWVkGAMgASgIEg4KBmZfcG9ydBgEIAEoDRIMCgRkYXRhGAUgASgMEicK", "YyLGAQoPRGV2aWNlUXVldWVJdGVtEgoKAmlkGAEgASgJEg8KB2Rldl9ldWkY",
"Bm9iamVjdBgGIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSEgoKaXNf", "AiABKAkSEQoJY29uZmlybWVkGAMgASgIEg4KBmZfcG9ydBgEIAEoDRIMCgRk",
"cGVuZGluZxgHIAEoCBISCgpmX2NudF9kb3duGAggASgNEhQKDGlzX2VuY3J5", "YXRhGAUgASgMEicKBm9iamVjdBgGIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5T",
"cHRlZBgJIAEoCCJJCh1FbnF1ZXVlRGV2aWNlUXVldWVJdGVtUmVxdWVzdBIo", "dHJ1Y3QSEgoKaXNfcGVuZGluZxgHIAEoCBISCgpmX2NudF9kb3duGAggASgN",
"CgpxdWV1ZV9pdGVtGAEgASgLMhQuYXBpLkRldmljZVF1ZXVlSXRlbSIsCh5F", "EhQKDGlzX2VuY3J5cHRlZBgJIAEoCCJJCh1FbnF1ZXVlRGV2aWNlUXVldWVJ",
"bnF1ZXVlRGV2aWNlUXVldWVJdGVtUmVzcG9uc2USCgoCaWQYASABKAkiKgoX", "dGVtUmVxdWVzdBIoCgpxdWV1ZV9pdGVtGAEgASgLMhQuYXBpLkRldmljZVF1",
"Rmx1c2hEZXZpY2VRdWV1ZVJlcXVlc3QSDwoHZGV2X2V1aRgBIAEoCSJBChpH", "ZXVlSXRlbSIsCh5FbnF1ZXVlRGV2aWNlUXVldWVJdGVtUmVzcG9uc2USCgoC",
"ZXREZXZpY2VRdWV1ZUl0ZW1zUmVxdWVzdBIPCgdkZXZfZXVpGAEgASgJEhIK", "aWQYASABKAkiKgoXRmx1c2hEZXZpY2VRdWV1ZVJlcXVlc3QSDwoHZGV2X2V1",
"CmNvdW50X29ubHkYAiABKAgiWAobR2V0RGV2aWNlUXVldWVJdGVtc1Jlc3Bv", "aRgBIAEoCSJBChpHZXREZXZpY2VRdWV1ZUl0ZW1zUmVxdWVzdBIPCgdkZXZf",
"bnNlEhMKC3RvdGFsX2NvdW50GAEgASgNEiQKBnJlc3VsdBgCIAMoCzIULmFw", "ZXVpGAEgASgJEhIKCmNvdW50X29ubHkYAiABKAgiWAobR2V0RGV2aWNlUXVl",
"aS5EZXZpY2VRdWV1ZUl0ZW0iKAoVRmx1c2hEZXZOb25jZXNSZXF1ZXN0Eg8K", "dWVJdGVtc1Jlc3BvbnNlEhMKC3RvdGFsX2NvdW50GAEgASgNEiQKBnJlc3Vs",
"B2Rldl9ldWkYASABKAkiLwocR2V0RGV2aWNlTmV4dEZDbnREb3duUmVxdWVz", "dBgCIAMoCzIULmFwaS5EZXZpY2VRdWV1ZUl0ZW0iKAoVRmx1c2hEZXZOb25j",
"dBIPCgdkZXZfZXVpGAEgASgJIjMKHUdldERldmljZU5leHRGQ250RG93blJl", "ZXNSZXF1ZXN0Eg8KB2Rldl9ldWkYASABKAkiLwocR2V0RGV2aWNlTmV4dEZD",
"c3BvbnNlEhIKCmZfY250X2Rvd24YASABKA0y4hEKDURldmljZVNlcnZpY2US", "bnREb3duUmVxdWVzdBIPCgdkZXZfZXVpGAEgASgJIjMKHUdldERldmljZU5l",
"UwoGQ3JlYXRlEhguYXBpLkNyZWF0ZURldmljZVJlcXVlc3QaFi5nb29nbGUu", "eHRGQ250RG93blJlc3BvbnNlEhIKCmZfY250X2Rvd24YASABKA0y4hEKDURl",
"cHJvdG9idWYuRW1wdHkiF4LT5JMCESIML2FwaS9kZXZpY2VzOgEqElQKA0dl", "dmljZVNlcnZpY2USUwoGQ3JlYXRlEhguYXBpLkNyZWF0ZURldmljZVJlcXVl",
"dBIVLmFwaS5HZXREZXZpY2VSZXF1ZXN0GhYuYXBpLkdldERldmljZVJlc3Bv", "c3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiF4LT5JMCESIML2FwaS9kZXZp",
"bnNlIh6C0+STAhgSFi9hcGkvZGV2aWNlcy97ZGV2X2V1aX0SZAoGVXBkYXRl", "Y2VzOgEqElQKA0dldBIVLmFwaS5HZXREZXZpY2VSZXF1ZXN0GhYuYXBpLkdl",
"EhguYXBpLlVwZGF0ZURldmljZVJlcXVlc3QaFi5nb29nbGUucHJvdG9idWYu", "dERldmljZVJlc3BvbnNlIh6C0+STAhgSFi9hcGkvZGV2aWNlcy97ZGV2X2V1",
"RW1wdHkiKILT5JMCIhodL2FwaS9kZXZpY2VzL3tkZXZpY2UuZGV2X2V1aX06", "aX0SZAoGVXBkYXRlEhguYXBpLlVwZGF0ZURldmljZVJlcXVlc3QaFi5nb29n",
"ASoSWgoGRGVsZXRlEhguYXBpLkRlbGV0ZURldmljZVJlcXVlc3QaFi5nb29n", "bGUucHJvdG9idWYuRW1wdHkiKILT5JMCIhodL2FwaS9kZXZpY2VzL3tkZXZp",
"bGUucHJvdG9idWYuRW1wdHkiHoLT5JMCGCoWL2FwaS9kZXZpY2VzL3tkZXZf", "Y2UuZGV2X2V1aX06ASoSWgoGRGVsZXRlEhguYXBpLkRlbGV0ZURldmljZVJl",
"ZXVpfRJPCgRMaXN0EhcuYXBpLkxpc3REZXZpY2VzUmVxdWVzdBoYLmFwaS5M", "cXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiHoLT5JMCGCoWL2FwaS9k",
"aXN0RGV2aWNlc1Jlc3BvbnNlIhSC0+STAg4SDC9hcGkvZGV2aWNlcxJ2CgpD", "ZXZpY2VzL3tkZXZfZXVpfRJPCgRMaXN0EhcuYXBpLkxpc3REZXZpY2VzUmVx",
"cmVhdGVLZXlzEhwuYXBpLkNyZWF0ZURldmljZUtleXNSZXF1ZXN0GhYuZ29v", "dWVzdBoYLmFwaS5MaXN0RGV2aWNlc1Jlc3BvbnNlIhSC0+STAg4SDC9hcGkv",
"Z2xlLnByb3RvYnVmLkVtcHR5IjKC0+STAiwiJy9hcGkvZGV2aWNlcy97ZGV2", "ZGV2aWNlcxJ2CgpDcmVhdGVLZXlzEhwuYXBpLkNyZWF0ZURldmljZUtleXNS",
"aWNlX2tleXMuZGV2X2V1aX0va2V5czoBKhJlCgdHZXRLZXlzEhkuYXBpLkdl", "ZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IjKC0+STAiwiJy9hcGkv",
"dERldmljZUtleXNSZXF1ZXN0GhouYXBpLkdldERldmljZUtleXNSZXNwb25z", "ZGV2aWNlcy97ZGV2aWNlX2tleXMuZGV2X2V1aX0va2V5czoBKhJlCgdHZXRL",
"ZSIjgtPkkwIdEhsvYXBpL2RldmljZXMve2Rldl9ldWl9L2tleXMSdgoKVXBk", "ZXlzEhkuYXBpLkdldERldmljZUtleXNSZXF1ZXN0GhouYXBpLkdldERldmlj",
"YXRlS2V5cxIcLmFwaS5VcGRhdGVEZXZpY2VLZXlzUmVxdWVzdBoWLmdvb2ds", "ZUtleXNSZXNwb25zZSIjgtPkkwIdEhsvYXBpL2RldmljZXMve2Rldl9ldWl9",
"ZS5wcm90b2J1Zi5FbXB0eSIygtPkkwIsGicvYXBpL2RldmljZXMve2Rldmlj", "L2tleXMSdgoKVXBkYXRlS2V5cxIcLmFwaS5VcGRhdGVEZXZpY2VLZXlzUmVx",
"ZV9rZXlzLmRldl9ldWl9L2tleXM6ASoSZwoKRGVsZXRlS2V5cxIcLmFwaS5E", "dWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eSIygtPkkwIsGicvYXBpL2Rl",
"ZWxldGVEZXZpY2VLZXlzUmVxdWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0", "dmljZXMve2RldmljZV9rZXlzLmRldl9ldWl9L2tleXM6ASoSZwoKRGVsZXRl",
"eSIjgtPkkwIdKhsvYXBpL2RldmljZXMve2Rldl9ldWl9L2tleXMSbwoORmx1", "S2V5cxIcLmFwaS5EZWxldGVEZXZpY2VLZXlzUmVxdWVzdBoWLmdvb2dsZS5w",
"c2hEZXZOb25jZXMSGi5hcGkuRmx1c2hEZXZOb25jZXNSZXF1ZXN0GhYuZ29v", "cm90b2J1Zi5FbXB0eSIjgtPkkwIdKhsvYXBpL2RldmljZXMve2Rldl9ldWl9",
"Z2xlLnByb3RvYnVmLkVtcHR5IimC0+STAiMqIS9hcGkvZGV2aWNlcy97ZGV2", "L2tleXMSbwoORmx1c2hEZXZOb25jZXMSGi5hcGkuRmx1c2hEZXZOb25jZXNS",
"X2V1aX0vZGV2LW5vbmNlcxJ8CghBY3RpdmF0ZRIaLmFwaS5BY3RpdmF0ZURl",
"dmljZVJlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiPILT5JMCNiIx",
"L2FwaS9kZXZpY2VzL3tkZXZpY2VfYWN0aXZhdGlvbi5kZXZfZXVpfS9hY3Rp",
"dmF0ZToBKhJtCgpEZWFjdGl2YXRlEhwuYXBpLkRlYWN0aXZhdGVEZXZpY2VS",
"ZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IimC0+STAiMqIS9hcGkv", "ZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IimC0+STAiMqIS9hcGkv",
"ZGV2aWNlcy97ZGV2X2V1aX0vYWN0aXZhdGlvbhJ9Cg1HZXRBY3RpdmF0aW9u", "ZGV2aWNlcy97ZGV2X2V1aX0vZGV2LW5vbmNlcxJ8CghBY3RpdmF0ZRIaLmFw",
"Eh8uYXBpLkdldERldmljZUFjdGl2YXRpb25SZXF1ZXN0GiAuYXBpLkdldERl", "aS5BY3RpdmF0ZURldmljZVJlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1w",
"dmljZUFjdGl2YXRpb25SZXNwb25zZSIpgtPkkwIjEiEvYXBpL2RldmljZXMv", "dHkiPILT5JMCNiIxL2FwaS9kZXZpY2VzL3tkZXZpY2VfYWN0aXZhdGlvbi5k",
"e2Rldl9ldWl9L2FjdGl2YXRpb24SgwEKEEdldFJhbmRvbURldkFkZHISHC5h", "ZXZfZXVpfS9hY3RpdmF0ZToBKhJtCgpEZWFjdGl2YXRlEhwuYXBpLkRlYWN0",
"cGkuR2V0UmFuZG9tRGV2QWRkclJlcXVlc3QaHS5hcGkuR2V0UmFuZG9tRGV2", "aXZhdGVEZXZpY2VSZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IimC",
"QWRkclJlc3BvbnNlIjKC0+STAiwiKi9hcGkvZGV2aWNlcy97ZGV2X2V1aX0v", "0+STAiMqIS9hcGkvZGV2aWNlcy97ZGV2X2V1aX0vYWN0aXZhdGlvbhJ9Cg1H",
"Z2V0LXJhbmRvbS1kZXYtYWRkchJxCgpHZXRNZXRyaWNzEhwuYXBpLkdldERl", "ZXRBY3RpdmF0aW9uEh8uYXBpLkdldERldmljZUFjdGl2YXRpb25SZXF1ZXN0",
"dmljZU1ldHJpY3NSZXF1ZXN0Gh0uYXBpLkdldERldmljZU1ldHJpY3NSZXNw", "GiAuYXBpLkdldERldmljZUFjdGl2YXRpb25SZXNwb25zZSIpgtPkkwIjEiEv",
"b25zZSImgtPkkwIgEh4vYXBpL2RldmljZXMve2Rldl9ldWl9L21ldHJpY3MS", "YXBpL2RldmljZXMve2Rldl9ldWl9L2FjdGl2YXRpb24SgwEKEEdldFJhbmRv",
"ggEKDkdldExpbmtNZXRyaWNzEiAuYXBpLkdldERldmljZUxpbmtNZXRyaWNz", "bURldkFkZHISHC5hcGkuR2V0UmFuZG9tRGV2QWRkclJlcXVlc3QaHS5hcGku",
"UmVxdWVzdBohLmFwaS5HZXREZXZpY2VMaW5rTWV0cmljc1Jlc3BvbnNlIiuC", "R2V0UmFuZG9tRGV2QWRkclJlc3BvbnNlIjKC0+STAiwiKi9hcGkvZGV2aWNl",
"0+STAiUSIy9hcGkvZGV2aWNlcy97ZGV2X2V1aX0vbGluay1tZXRyaWNzEoYB", "cy97ZGV2X2V1aX0vZ2V0LXJhbmRvbS1kZXYtYWRkchJxCgpHZXRNZXRyaWNz",
"CgdFbnF1ZXVlEiIuYXBpLkVucXVldWVEZXZpY2VRdWV1ZUl0ZW1SZXF1ZXN0", "EhwuYXBpLkdldERldmljZU1ldHJpY3NSZXF1ZXN0Gh0uYXBpLkdldERldmlj",
"GiMuYXBpLkVucXVldWVEZXZpY2VRdWV1ZUl0ZW1SZXNwb25zZSIygtPkkwIs", "ZU1ldHJpY3NSZXNwb25zZSImgtPkkwIgEh4vYXBpL2RldmljZXMve2Rldl9l",
"IicvYXBpL2RldmljZXMve3F1ZXVlX2l0ZW0uZGV2X2V1aX0vcXVldWU6ASoS", "dWl9L21ldHJpY3MSggEKDkdldExpbmtNZXRyaWNzEiAuYXBpLkdldERldmlj",
"aAoKRmx1c2hRdWV1ZRIcLmFwaS5GbHVzaERldmljZVF1ZXVlUmVxdWVzdBoW", "ZUxpbmtNZXRyaWNzUmVxdWVzdBohLmFwaS5HZXREZXZpY2VMaW5rTWV0cmlj",
"Lmdvb2dsZS5wcm90b2J1Zi5FbXB0eSIkgtPkkwIeKhwvYXBpL2RldmljZXMv", "c1Jlc3BvbnNlIiuC0+STAiUSIy9hcGkvZGV2aWNlcy97ZGV2X2V1aX0vbGlu",
"e2Rldl9ldWl9L3F1ZXVlEnMKCEdldFF1ZXVlEh8uYXBpLkdldERldmljZVF1", "ay1tZXRyaWNzEoYBCgdFbnF1ZXVlEiIuYXBpLkVucXVldWVEZXZpY2VRdWV1",
"ZXVlSXRlbXNSZXF1ZXN0GiAuYXBpLkdldERldmljZVF1ZXVlSXRlbXNSZXNw", "ZUl0ZW1SZXF1ZXN0GiMuYXBpLkVucXVldWVEZXZpY2VRdWV1ZUl0ZW1SZXNw",
"b25zZSIkgtPkkwIeEhwvYXBpL2RldmljZXMve2Rldl9ldWl9L3F1ZXVlEo8B", "b25zZSIygtPkkwIsIicvYXBpL2RldmljZXMve3F1ZXVlX2l0ZW0uZGV2X2V1",
"Cg9HZXROZXh0RkNudERvd24SIS5hcGkuR2V0RGV2aWNlTmV4dEZDbnREb3du", "aX0vcXVldWU6ASoSaAoKRmx1c2hRdWV1ZRIcLmFwaS5GbHVzaERldmljZVF1",
"UmVxdWVzdBoiLmFwaS5HZXREZXZpY2VOZXh0RkNudERvd25SZXNwb25zZSI1", "ZXVlUmVxdWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eSIkgtPkkwIeKhwv",
"gtPkkwIvIiovYXBpL2RldmljZXMve2Rldl9ldWl9L2dldC1uZXh0LWYtY250", "YXBpL2RldmljZXMve2Rldl9ldWl9L3F1ZXVlEnMKCEdldFF1ZXVlEh8uYXBp",
"LWRvd246ASpCYwoRaW8uY2hpcnBzdGFjay5hcGlCC0RldmljZVByb3RvUAFa", "LkdldERldmljZVF1ZXVlSXRlbXNSZXF1ZXN0GiAuYXBpLkdldERldmljZVF1",
"LmdpdGh1Yi5jb20vY2hpcnBzdGFjay9jaGlycHN0YWNrL2FwaS9nby92NC9h", "ZXVlSXRlbXNSZXNwb25zZSIkgtPkkwIeEhwvYXBpL2RldmljZXMve2Rldl9l",
"cGmqAg5DaGlycHN0YWNrLkFwaWIGcHJvdG8z")); "dWl9L3F1ZXVlEo8BCg9HZXROZXh0RkNudERvd24SIS5hcGkuR2V0RGV2aWNl",
"TmV4dEZDbnREb3duUmVxdWVzdBoiLmFwaS5HZXREZXZpY2VOZXh0RkNudERv",
"d25SZXNwb25zZSI1gtPkkwIvIiovYXBpL2RldmljZXMve2Rldl9ldWl9L2dl",
"dC1uZXh0LWYtY250LWRvd246ASpCYwoRaW8uY2hpcnBzdGFjay5hcGlCC0Rl",
"dmljZVByb3RvUAFaLmdpdGh1Yi5jb20vY2hpcnBzdGFjay9jaGlycHN0YWNr",
"L2FwaS9nby92NC9hcGmqAg5DaGlycHN0YWNrLkFwaWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Chirpstack.Common.CommonReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, }, new pbr::FileDescriptor[] { global::Chirpstack.Common.CommonReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
@ -193,7 +194,7 @@ namespace Chirpstack.Api {
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.ActivateDeviceRequest), global::Chirpstack.Api.ActivateDeviceRequest.Parser, new[]{ "DeviceActivation" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.ActivateDeviceRequest), global::Chirpstack.Api.ActivateDeviceRequest.Parser, new[]{ "DeviceActivation" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.DeactivateDeviceRequest), global::Chirpstack.Api.DeactivateDeviceRequest.Parser, new[]{ "DevEui" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.DeactivateDeviceRequest), global::Chirpstack.Api.DeactivateDeviceRequest.Parser, new[]{ "DevEui" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceActivationRequest), global::Chirpstack.Api.GetDeviceActivationRequest.Parser, new[]{ "DevEui" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceActivationRequest), global::Chirpstack.Api.GetDeviceActivationRequest.Parser, new[]{ "DevEui" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceActivationResponse), global::Chirpstack.Api.GetDeviceActivationResponse.Parser, new[]{ "DeviceActivation" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceActivationResponse), global::Chirpstack.Api.GetDeviceActivationResponse.Parser, new[]{ "DeviceActivation", "JoinServerContext" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetRandomDevAddrRequest), global::Chirpstack.Api.GetRandomDevAddrRequest.Parser, new[]{ "DevEui" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetRandomDevAddrRequest), global::Chirpstack.Api.GetRandomDevAddrRequest.Parser, new[]{ "DevEui" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetRandomDevAddrResponse), global::Chirpstack.Api.GetRandomDevAddrResponse.Parser, new[]{ "DevAddr" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetRandomDevAddrResponse), global::Chirpstack.Api.GetRandomDevAddrResponse.Parser, new[]{ "DevAddr" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceMetricsRequest), global::Chirpstack.Api.GetDeviceMetricsRequest.Parser, new[]{ "DevEui", "Start", "End", "Aggregation" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Api.GetDeviceMetricsRequest), global::Chirpstack.Api.GetDeviceMetricsRequest.Parser, new[]{ "DevEui", "Start", "End", "Aggregation" }, null, null, null, null),
@ -5865,6 +5866,7 @@ namespace Chirpstack.Api {
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public GetDeviceActivationResponse(GetDeviceActivationResponse other) : this() { public GetDeviceActivationResponse(GetDeviceActivationResponse other) : this() {
deviceActivation_ = other.deviceActivation_ != null ? other.deviceActivation_.Clone() : null; deviceActivation_ = other.deviceActivation_ != null ? other.deviceActivation_.Clone() : null;
joinServerContext_ = other.joinServerContext_ != null ? other.joinServerContext_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
} }
@ -5889,6 +5891,24 @@ namespace Chirpstack.Api {
} }
} }
/// <summary>Field number for the "join_server_context" field.</summary>
public const int JoinServerContextFieldNumber = 2;
private global::Chirpstack.Common.JoinServerContext joinServerContext_;
/// <summary>
/// Join-Server context.
/// A non-empty value indicatest that ChirpStack does not have access to
/// the AppSKey and that the encryption / decryption of the payloads is
/// the responsibility of the end-application.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Chirpstack.Common.JoinServerContext JoinServerContext {
get { return joinServerContext_; }
set {
joinServerContext_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) { public override bool Equals(object other) {
@ -5905,6 +5925,7 @@ namespace Chirpstack.Api {
return true; return true;
} }
if (!object.Equals(DeviceActivation, other.DeviceActivation)) return false; if (!object.Equals(DeviceActivation, other.DeviceActivation)) return false;
if (!object.Equals(JoinServerContext, other.JoinServerContext)) return false;
return Equals(_unknownFields, other._unknownFields); return Equals(_unknownFields, other._unknownFields);
} }
@ -5913,6 +5934,7 @@ namespace Chirpstack.Api {
public override int GetHashCode() { public override int GetHashCode() {
int hash = 1; int hash = 1;
if (deviceActivation_ != null) hash ^= DeviceActivation.GetHashCode(); if (deviceActivation_ != null) hash ^= DeviceActivation.GetHashCode();
if (joinServerContext_ != null) hash ^= JoinServerContext.GetHashCode();
if (_unknownFields != null) { if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode(); hash ^= _unknownFields.GetHashCode();
} }
@ -5935,6 +5957,10 @@ namespace Chirpstack.Api {
output.WriteRawTag(10); output.WriteRawTag(10);
output.WriteMessage(DeviceActivation); output.WriteMessage(DeviceActivation);
} }
if (joinServerContext_ != null) {
output.WriteRawTag(18);
output.WriteMessage(JoinServerContext);
}
if (_unknownFields != null) { if (_unknownFields != null) {
_unknownFields.WriteTo(output); _unknownFields.WriteTo(output);
} }
@ -5949,6 +5975,10 @@ namespace Chirpstack.Api {
output.WriteRawTag(10); output.WriteRawTag(10);
output.WriteMessage(DeviceActivation); output.WriteMessage(DeviceActivation);
} }
if (joinServerContext_ != null) {
output.WriteRawTag(18);
output.WriteMessage(JoinServerContext);
}
if (_unknownFields != null) { if (_unknownFields != null) {
_unknownFields.WriteTo(ref output); _unknownFields.WriteTo(ref output);
} }
@ -5962,6 +5992,9 @@ namespace Chirpstack.Api {
if (deviceActivation_ != null) { if (deviceActivation_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(DeviceActivation); size += 1 + pb::CodedOutputStream.ComputeMessageSize(DeviceActivation);
} }
if (joinServerContext_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(JoinServerContext);
}
if (_unknownFields != null) { if (_unknownFields != null) {
size += _unknownFields.CalculateSize(); size += _unknownFields.CalculateSize();
} }
@ -5980,6 +6013,12 @@ namespace Chirpstack.Api {
} }
DeviceActivation.MergeFrom(other.DeviceActivation); DeviceActivation.MergeFrom(other.DeviceActivation);
} }
if (other.joinServerContext_ != null) {
if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
}
JoinServerContext.MergeFrom(other.JoinServerContext);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
} }
@ -6002,6 +6041,13 @@ namespace Chirpstack.Api {
input.ReadMessage(DeviceActivation); input.ReadMessage(DeviceActivation);
break; break;
} }
case 18: {
if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
}
input.ReadMessage(JoinServerContext);
break;
}
} }
} }
#endif #endif
@ -6024,6 +6070,13 @@ namespace Chirpstack.Api {
input.ReadMessage(DeviceActivation); input.ReadMessage(DeviceActivation);
break; break;
} }
case 18: {
if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
}
input.ReadMessage(JoinServerContext);
break;
}
} }
} }
} }

View File

@ -33,37 +33,40 @@ namespace Chirpstack.Common {
"ZXN0YW1wcxgCIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASJwoI", "ZXN0YW1wcxgCIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASJwoI",
"ZGF0YXNldHMYAyADKAsyFS5jb21tb24uTWV0cmljRGF0YXNldBIgCgRraW5k", "ZGF0YXNldHMYAyADKAsyFS5jb21tb24uTWV0cmljRGF0YXNldBIgCgRraW5k",
"GAQgASgOMhIuY29tbW9uLk1ldHJpY0tpbmQiLAoNTWV0cmljRGF0YXNldBIN", "GAQgASgOMhIuY29tbW9uLk1ldHJpY0tpbmQiLAoNTWV0cmljRGF0YXNldBIN",
"CgVsYWJlbBgBIAEoCRIMCgRkYXRhGAIgAygCKiwKCk1vZHVsYXRpb24SCAoE", "CgVsYWJlbBgBIAEoCRIMCgRkYXRhGAIgAygCIlMKEUpvaW5TZXJ2ZXJDb250",
"TE9SQRAAEgcKA0ZTSxABEgsKB0xSX0ZIU1MQAiqqAQoGUmVnaW9uEgkKBUVV", "ZXh0EhYKDnNlc3Npb25fa2V5X2lkGAEgASgJEiYKCWFwcF9zX2tleRgCIAEo",
"ODY4EAASCQoFVVM5MTUQAhIJCgVDTjc3ORADEgkKBUVVNDMzEAQSCQoFQVU5", "CzITLmNvbW1vbi5LZXlFbnZlbG9wZSosCgpNb2R1bGF0aW9uEggKBExPUkEQ",
"MTUQBRIJCgVDTjQ3MBAGEgkKBUFTOTIzEAcSCwoHQVM5MjNfMhAMEgsKB0FT", "ABIHCgNGU0sQARILCgdMUl9GSFNTEAIqqgEKBlJlZ2lvbhIJCgVFVTg2OBAA",
"OTIzXzMQDRILCgdBUzkyM180EA4SCQoFS1I5MjAQCBIJCgVJTjg2NRAJEgkK", "EgkKBVVTOTE1EAISCQoFQ043NzkQAxIJCgVFVTQzMxAEEgkKBUFVOTE1EAUS",
"BVJVODY0EAoSCwoHSVNNMjQwMBALKrMBCgVNVHlwZRIQCgxKT0lOX1JFUVVF", "CQoFQ040NzAQBhIJCgVBUzkyMxAHEgsKB0FTOTIzXzIQDBILCgdBUzkyM18z",
"U1QQABIPCgtKT0lOX0FDQ0VQVBABEhcKE1VOQ09ORklSTUVEX0RBVEFfVVAQ", "EA0SCwoHQVM5MjNfNBAOEgkKBUtSOTIwEAgSCQoFSU44NjUQCRIJCgVSVTg2",
"AhIZChVVTkNPTkZJUk1FRF9EQVRBX0RPV04QAxIVChFDT05GSVJNRURfREFU", "NBAKEgsKB0lTTTI0MDAQCyqzAQoFTVR5cGUSEAoMSk9JTl9SRVFVRVNUEAAS",
"QV9VUBAEEhcKE0NPTkZJUk1FRF9EQVRBX0RPV04QBRISCg5SRUpPSU5fUkVR", "DwoLSk9JTl9BQ0NFUFQQARIXChNVTkNPTkZJUk1FRF9EQVRBX1VQEAISGQoV",
"VUVTVBAGEg8KC1BST1BSSUVUQVJZEAcqfgoKTWFjVmVyc2lvbhIRCg1MT1JB", "VU5DT05GSVJNRURfREFUQV9ET1dOEAMSFQoRQ09ORklSTUVEX0RBVEFfVVAQ",
"V0FOXzFfMF8wEAASEQoNTE9SQVdBTl8xXzBfMRABEhEKDUxPUkFXQU5fMV8w", "BBIXChNDT05GSVJNRURfREFUQV9ET1dOEAUSEgoOUkVKT0lOX1JFUVVFU1QQ",
"XzIQAhIRCg1MT1JBV0FOXzFfMF8zEAMSEQoNTE9SQVdBTl8xXzBfNBAEEhEK", "BhIPCgtQUk9QUklFVEFSWRAHKn4KCk1hY1ZlcnNpb24SEQoNTE9SQVdBTl8x",
"DUxPUkFXQU5fMV8xXzAQBSplChFSZWdQYXJhbXNSZXZpc2lvbhIFCgFBEAAS", "XzBfMBAAEhEKDUxPUkFXQU5fMV8wXzEQARIRCg1MT1JBV0FOXzFfMF8yEAIS",
"BQoBQhABEg8KC1JQMDAyXzFfMF8wEAISDwoLUlAwMDJfMV8wXzEQAxIPCgtS", "EQoNTE9SQVdBTl8xXzBfMxADEhEKDUxPUkFXQU5fMV8wXzQQBBIRCg1MT1JB",
"UDAwMl8xXzBfMhAEEg8KC1JQMDAyXzFfMF8zEAUqjgEKDkxvY2F0aW9uU291", "V0FOXzFfMV8wEAUqZQoRUmVnUGFyYW1zUmV2aXNpb24SBQoBQRAAEgUKAUIQ",
"cmNlEgsKB1VOS05PV04QABIHCgNHUFMQARIKCgZDT05GSUcQAhIVChFHRU9f", "ARIPCgtSUDAwMl8xXzBfMBACEg8KC1JQMDAyXzFfMF8xEAMSDwoLUlAwMDJf",
"UkVTT0xWRVJfVERPQRADEhUKEUdFT19SRVNPTFZFUl9SU1NJEAQSFQoRR0VP", "MV8wXzIQBBIPCgtSUDAwMl8xXzBfMxAFKo4BCg5Mb2NhdGlvblNvdXJjZRIL",
"X1JFU09MVkVSX0dOU1MQBRIVChFHRU9fUkVTT0xWRVJfV0lGSRAGKisKC0Fn", "CgdVTktOT1dOEAASBwoDR1BTEAESCgoGQ09ORklHEAISFQoRR0VPX1JFU09M",
"Z3JlZ2F0aW9uEggKBEhPVVIQABIHCgNEQVkQARIJCgVNT05USBACKjIKCk1l", "VkVSX1RET0EQAxIVChFHRU9fUkVTT0xWRVJfUlNTSRAEEhUKEUdFT19SRVNP",
"dHJpY0tpbmQSCwoHQ09VTlRFUhAAEgwKCEFCU09MVVRFEAESCQoFR0FVR0UQ", "TFZFUl9HTlNTEAUSFQoRR0VPX1JFU09MVkVSX1dJRkkQBiorCgtBZ2dyZWdh",
"Aio0CgtEZXZpY2VDbGFzcxILCgdDTEFTU19BEAASCwoHQ0xBU1NfQhABEgsK", "dGlvbhIICgRIT1VSEAASBwoDREFZEAESCQoFTU9OVEgQAioyCgpNZXRyaWNL",
"B0NMQVNTX0MQAkJpChFpby5jaGlycHN0YWNrLmFwaUILQ29tbW9uUHJvdG9Q", "aW5kEgsKB0NPVU5URVIQABIMCghBQlNPTFVURRABEgkKBUdBVUdFEAIqNAoL",
"AVoxZ2l0aHViLmNvbS9jaGlycHN0YWNrL2NoaXJwc3RhY2svYXBpL2dvL3Y0", "RGV2aWNlQ2xhc3MSCwoHQ0xBU1NfQRAAEgsKB0NMQVNTX0IQARILCgdDTEFT",
"L2NvbW1vbqoCEUNoaXJwc3RhY2suQ29tbW9uYgZwcm90bzM=")); "U19DEAJCaQoRaW8uY2hpcnBzdGFjay5hcGlCC0NvbW1vblByb3RvUAFaMWdp",
"dGh1Yi5jb20vY2hpcnBzdGFjay9jaGlycHN0YWNrL2FwaS9nby92NC9jb21t",
"b26qAhFDaGlycHN0YWNrLkNvbW1vbmIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, }, new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Chirpstack.Common.Modulation), typeof(global::Chirpstack.Common.Region), typeof(global::Chirpstack.Common.MType), typeof(global::Chirpstack.Common.MacVersion), typeof(global::Chirpstack.Common.RegParamsRevision), typeof(global::Chirpstack.Common.LocationSource), typeof(global::Chirpstack.Common.Aggregation), typeof(global::Chirpstack.Common.MetricKind), typeof(global::Chirpstack.Common.DeviceClass), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Chirpstack.Common.Modulation), typeof(global::Chirpstack.Common.Region), typeof(global::Chirpstack.Common.MType), typeof(global::Chirpstack.Common.MacVersion), typeof(global::Chirpstack.Common.RegParamsRevision), typeof(global::Chirpstack.Common.LocationSource), typeof(global::Chirpstack.Common.Aggregation), typeof(global::Chirpstack.Common.MetricKind), typeof(global::Chirpstack.Common.DeviceClass), }, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.Location), global::Chirpstack.Common.Location.Parser, new[]{ "Latitude", "Longitude", "Altitude", "Source", "Accuracy" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.Location), global::Chirpstack.Common.Location.Parser, new[]{ "Latitude", "Longitude", "Altitude", "Source", "Accuracy" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.KeyEnvelope), global::Chirpstack.Common.KeyEnvelope.Parser, new[]{ "KekLabel", "AesKey" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.KeyEnvelope), global::Chirpstack.Common.KeyEnvelope.Parser, new[]{ "KekLabel", "AesKey" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.Metric), global::Chirpstack.Common.Metric.Parser, new[]{ "Name", "Timestamps", "Datasets", "Kind" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.Metric), global::Chirpstack.Common.Metric.Parser, new[]{ "Name", "Timestamps", "Datasets", "Kind" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.MetricDataset), global::Chirpstack.Common.MetricDataset.Parser, new[]{ "Label", "Data" }, null, null, null, null) new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.MetricDataset), global::Chirpstack.Common.MetricDataset.Parser, new[]{ "Label", "Data" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Common.JoinServerContext), global::Chirpstack.Common.JoinServerContext.Parser, new[]{ "SessionKeyId", "AppSKey" }, null, null, null, null)
})); }));
} }
#endregion #endregion
@ -1375,6 +1378,250 @@ namespace Chirpstack.Common {
} }
/// <summary>
/// Join-Server context.
/// </summary>
public sealed partial class JoinServerContext : pb::IMessage<JoinServerContext>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<JoinServerContext> _parser = new pb::MessageParser<JoinServerContext>(() => new JoinServerContext());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<JoinServerContext> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Common.CommonReflection.Descriptor.MessageTypes[4]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext(JoinServerContext other) : this() {
sessionKeyId_ = other.sessionKeyId_;
appSKey_ = other.appSKey_ != null ? other.appSKey_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext Clone() {
return new JoinServerContext(this);
}
/// <summary>Field number for the "session_key_id" field.</summary>
public const int SessionKeyIdFieldNumber = 1;
private string sessionKeyId_ = "";
/// <summary>
/// Session-key ID.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string SessionKeyId {
get { return sessionKeyId_; }
set {
sessionKeyId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "app_s_key" field.</summary>
public const int AppSKeyFieldNumber = 2;
private global::Chirpstack.Common.KeyEnvelope appSKey_;
/// <summary>
/// AppSKey envelope.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Chirpstack.Common.KeyEnvelope AppSKey {
get { return appSKey_; }
set {
appSKey_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as JoinServerContext);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(JoinServerContext other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (SessionKeyId != other.SessionKeyId) return false;
if (!object.Equals(AppSKey, other.AppSKey)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (SessionKeyId.Length != 0) hash ^= SessionKeyId.GetHashCode();
if (appSKey_ != null) hash ^= AppSKey.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (SessionKeyId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(SessionKeyId);
}
if (appSKey_ != null) {
output.WriteRawTag(18);
output.WriteMessage(AppSKey);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (SessionKeyId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(SessionKeyId);
}
if (appSKey_ != null) {
output.WriteRawTag(18);
output.WriteMessage(AppSKey);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (SessionKeyId.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(SessionKeyId);
}
if (appSKey_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(AppSKey);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(JoinServerContext other) {
if (other == null) {
return;
}
if (other.SessionKeyId.Length != 0) {
SessionKeyId = other.SessionKeyId;
}
if (other.appSKey_ != null) {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
AppSKey.MergeFrom(other.AppSKey);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
SessionKeyId = input.ReadString();
break;
}
case 18: {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
input.ReadMessage(AppSKey);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
SessionKeyId = input.ReadString();
break;
}
case 18: {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
input.ReadMessage(AppSKey);
break;
}
}
}
}
#endif
}
#endregion #endregion
} }

View File

@ -37,73 +37,70 @@ namespace Chirpstack.Integration {
"dHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEicwoRVXBsaW5r", "dHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEicwoRVXBsaW5r",
"UmVsYXlSeEluZm8SDwoHZGV2X2V1aRgBIAEoCRIRCglmcmVxdWVuY3kYAiAB", "UmVsYXlSeEluZm8SDwoHZGV2X2V1aRgBIAEoCRIRCglmcmVxdWVuY3kYAiAB",
"KA0SCgoCZHIYAyABKA0SCwoDc25yGAQgASgFEgwKBHJzc2kYBSABKAUSEwoL", "KA0SCgoCZHIYAyABKA0SCwoDc25yGAQgASgFEgwKBHJzc2kYBSABKAUSEwoL",
"d29yX2NoYW5uZWwYBiABKA0iUwoRSm9pblNlcnZlckNvbnRleHQSFgoOc2Vz", "d29yX2NoYW5uZWwYBiABKA0iyAMKC1VwbGlua0V2ZW50EhgKEGRlZHVwbGlj",
"c2lvbl9rZXlfaWQYASABKAkSJgoJYXBwX3Nfa2V5GAIgASgLMhMuY29tbW9u", "YXRpb25faWQYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5wcm90b2J1",
"LktleUVudmVsb3BlIs0DCgtVcGxpbmtFdmVudBIYChBkZWR1cGxpY2F0aW9u", "Zi5UaW1lc3RhbXASLAoLZGV2aWNlX2luZm8YAyABKAsyFy5pbnRlZ3JhdGlv",
"X2lkGAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGlt", "bi5EZXZpY2VJbmZvEhAKCGRldl9hZGRyGAQgASgJEgsKA2FkchgFIAEoCBIK",
"ZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50ZWdyYXRpb24uRGV2", "CgJkchgGIAEoDRINCgVmX2NudBgHIAEoDRIOCgZmX3BvcnQYCCABKA0SEQoJ",
"aWNlSW5mbxIQCghkZXZfYWRkchgEIAEoCRILCgNhZHIYBSABKAgSCgoCZHIY", "Y29uZmlybWVkGAkgASgIEgwKBGRhdGEYCiABKAwSJwoGb2JqZWN0GAsgASgL",
"BiABKA0SDQoFZl9jbnQYByABKA0SDgoGZl9wb3J0GAggASgNEhEKCWNvbmZp", "MhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIhCgdyeF9pbmZvGAwgAygLMhAu",
"cm1lZBgJIAEoCBIMCgRkYXRhGAogASgMEicKBm9iamVjdBgLIAEoCzIXLmdv", "Z3cuVXBsaW5rUnhJbmZvEiEKB3R4X2luZm8YDSABKAsyEC5ndy5VcGxpbmtU",
"b2dsZS5wcm90b2J1Zi5TdHJ1Y3QSIQoHcnhfaW5mbxgMIAMoCzIQLmd3LlVw", "eEluZm8SNQoNcmVsYXlfcnhfaW5mbxgOIAEoCzIeLmludGVncmF0aW9uLlVw",
"bGlua1J4SW5mbxIhCgd0eF9pbmZvGA0gASgLMhAuZ3cuVXBsaW5rVHhJbmZv", "bGlua1JlbGF5UnhJbmZvEjYKE2pvaW5fc2VydmVyX2NvbnRleHQYDyABKAsy",
"EjUKDXJlbGF5X3J4X2luZm8YDiABKAsyHi5pbnRlZ3JhdGlvbi5VcGxpbmtS", "GS5jb21tb24uSm9pblNlcnZlckNvbnRleHQi/gEKCUpvaW5FdmVudBIYChBk",
"ZWxheVJ4SW5mbxI7ChNqb2luX3NlcnZlcl9jb250ZXh0GA8gASgLMh4uaW50",
"ZWdyYXRpb24uSm9pblNlcnZlckNvbnRleHQigwIKCUpvaW5FdmVudBIYChBk",
"ZWR1cGxpY2F0aW9uX2lkGAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUu", "ZWR1cGxpY2F0aW9uX2lkGAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUu",
"cHJvdG9idWYuVGltZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50", "cHJvdG9idWYuVGltZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50",
"ZWdyYXRpb24uRGV2aWNlSW5mbxIQCghkZXZfYWRkchgEIAEoCRI1Cg1yZWxh", "ZWdyYXRpb24uRGV2aWNlSW5mbxIQCghkZXZfYWRkchgEIAEoCRI1Cg1yZWxh",
"eV9yeF9pbmZvGAUgASgLMh4uaW50ZWdyYXRpb24uVXBsaW5rUmVsYXlSeElu", "eV9yeF9pbmZvGAUgASgLMh4uaW50ZWdyYXRpb24uVXBsaW5rUmVsYXlSeElu",
"Zm8SOwoTam9pbl9zZXJ2ZXJfY29udGV4dBgGIAEoCzIeLmludGVncmF0aW9u", "Zm8SNgoTam9pbl9zZXJ2ZXJfY29udGV4dBgGIAEoCzIZLmNvbW1vbi5Kb2lu",
"LkpvaW5TZXJ2ZXJDb250ZXh0Ir0BCghBY2tFdmVudBIYChBkZWR1cGxpY2F0", "U2VydmVyQ29udGV4dCK9AQoIQWNrRXZlbnQSGAoQZGVkdXBsaWNhdGlvbl9p",
"aW9uX2lkGAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYu", "ZBgBIAEoCRIoCgR0aW1lGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVz",
"VGltZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50ZWdyYXRpb24u", "dGFtcBIsCgtkZXZpY2VfaW5mbxgDIAEoCzIXLmludGVncmF0aW9uLkRldmlj",
"RGV2aWNlSW5mbxIVCg1xdWV1ZV9pdGVtX2lkGAQgASgJEhQKDGFja25vd2xl", "ZUluZm8SFQoNcXVldWVfaXRlbV9pZBgEIAEoCRIUCgxhY2tub3dsZWRnZWQY",
"ZGdlZBgFIAEoCBISCgpmX2NudF9kb3duGAYgASgNIt0BCgpUeEFja0V2ZW50", "BSABKAgSEgoKZl9jbnRfZG93bhgGIAEoDSLdAQoKVHhBY2tFdmVudBITCgtk",
"EhMKC2Rvd25saW5rX2lkGAEgASgNEigKBHRpbWUYAiABKAsyGi5nb29nbGUu", "b3dubGlua19pZBgBIAEoDRIoCgR0aW1lGAIgASgLMhouZ29vZ2xlLnByb3Rv",
"cHJvdG9idWYuVGltZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50", "YnVmLlRpbWVzdGFtcBIsCgtkZXZpY2VfaW5mbxgDIAEoCzIXLmludGVncmF0",
"ZWdyYXRpb24uRGV2aWNlSW5mbxIVCg1xdWV1ZV9pdGVtX2lkGAQgASgJEhIK", "aW9uLkRldmljZUluZm8SFQoNcXVldWVfaXRlbV9pZBgEIAEoCRISCgpmX2Nu",
"CmZfY250X2Rvd24YBSABKA0SEgoKZ2F0ZXdheV9pZBgGIAEoCRIjCgd0eF9p", "dF9kb3duGAUgASgNEhIKCmdhdGV3YXlfaWQYBiABKAkSIwoHdHhfaW5mbxgH",
"bmZvGAcgASgLMhIuZ3cuRG93bmxpbmtUeEluZm8ipgIKCExvZ0V2ZW50EigK", "IAEoCzISLmd3LkRvd25saW5rVHhJbmZvIqYCCghMb2dFdmVudBIoCgR0aW1l",
"BHRpbWUYASABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwKC2Rl", "GAEgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCgtkZXZpY2Vf",
"dmljZV9pbmZvGAIgASgLMhcuaW50ZWdyYXRpb24uRGV2aWNlSW5mbxIkCgVs", "aW5mbxgCIAEoCzIXLmludGVncmF0aW9uLkRldmljZUluZm8SJAoFbGV2ZWwY",
"ZXZlbBgDIAEoDjIVLmludGVncmF0aW9uLkxvZ0xldmVsEiIKBGNvZGUYBCAB", "AyABKA4yFS5pbnRlZ3JhdGlvbi5Mb2dMZXZlbBIiCgRjb2RlGAQgASgOMhQu",
"KA4yFC5pbnRlZ3JhdGlvbi5Mb2dDb2RlEhMKC2Rlc2NyaXB0aW9uGAUgASgJ", "aW50ZWdyYXRpb24uTG9nQ29kZRITCgtkZXNjcmlwdGlvbhgFIAEoCRIzCgdj",
"EjMKB2NvbnRleHQYBiADKAsyIi5pbnRlZ3JhdGlvbi5Mb2dFdmVudC5Db250", "b250ZXh0GAYgAygLMiIuaW50ZWdyYXRpb24uTG9nRXZlbnQuQ29udGV4dEVu",
"ZXh0RW50cnkaLgoMQ29udGV4dEVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1", "dHJ5Gi4KDENvbnRleHRFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB",
"ZRgCIAEoCToCOAEi6AEKC1N0YXR1c0V2ZW50EhgKEGRlZHVwbGljYXRpb25f", "KAk6AjgBIugBCgtTdGF0dXNFdmVudBIYChBkZWR1cGxpY2F0aW9uX2lkGAEg",
"aWQYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1l", "ASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w",
"c3RhbXASLAoLZGV2aWNlX2luZm8YAyABKAsyFy5pbnRlZ3JhdGlvbi5EZXZp", "EiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50ZWdyYXRpb24uRGV2aWNlSW5m",
"Y2VJbmZvEg4KBm1hcmdpbhgFIAEoBRIdChVleHRlcm5hbF9wb3dlcl9zb3Vy", "bxIOCgZtYXJnaW4YBSABKAUSHQoVZXh0ZXJuYWxfcG93ZXJfc291cmNlGAYg",
"Y2UYBiABKAgSIQoZYmF0dGVyeV9sZXZlbF91bmF2YWlsYWJsZRgHIAEoCBIV", "ASgIEiEKGWJhdHRlcnlfbGV2ZWxfdW5hdmFpbGFibGUYByABKAgSFQoNYmF0",
"Cg1iYXR0ZXJ5X2xldmVsGAggASgCIqUBCg1Mb2NhdGlvbkV2ZW50EhgKEGRl", "dGVyeV9sZXZlbBgIIAEoAiKlAQoNTG9jYXRpb25FdmVudBIYChBkZWR1cGxp",
"ZHVwbGljYXRpb25faWQYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5w", "Y2F0aW9uX2lkGAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUucHJvdG9i",
"cm90b2J1Zi5UaW1lc3RhbXASLAoLZGV2aWNlX2luZm8YAyABKAsyFy5pbnRl", "dWYuVGltZXN0YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50ZWdyYXRp",
"Z3JhdGlvbi5EZXZpY2VJbmZvEiIKCGxvY2F0aW9uGAQgASgLMhAuY29tbW9u", "b24uRGV2aWNlSW5mbxIiCghsb2NhdGlvbhgEIAEoCzIQLmNvbW1vbi5Mb2Nh",
"LkxvY2F0aW9uItsBChBJbnRlZ3JhdGlvbkV2ZW50EhgKEGRlZHVwbGljYXRp", "dGlvbiLbAQoQSW50ZWdyYXRpb25FdmVudBIYChBkZWR1cGxpY2F0aW9uX2lk",
"b25faWQYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5U", "GAEgASgJEigKBHRpbWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0",
"aW1lc3RhbXASLAoLZGV2aWNlX2luZm8YAyABKAsyFy5pbnRlZ3JhdGlvbi5E", "YW1wEiwKC2RldmljZV9pbmZvGAMgASgLMhcuaW50ZWdyYXRpb24uRGV2aWNl",
"ZXZpY2VJbmZvEhgKEGludGVncmF0aW9uX25hbWUYBCABKAkSEgoKZXZlbnRf", "SW5mbxIYChBpbnRlZ3JhdGlvbl9uYW1lGAQgASgJEhIKCmV2ZW50X3R5cGUY",
"dHlwZRgFIAEoCRInCgZvYmplY3QYBiABKAsyFy5nb29nbGUucHJvdG9idWYu", "BSABKAkSJwoGb2JqZWN0GAYgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVj",
"U3RydWN0IogBCg9Eb3dubGlua0NvbW1hbmQSCgoCaWQYASABKAkSDwoHZGV2", "dCKIAQoPRG93bmxpbmtDb21tYW5kEgoKAmlkGAEgASgJEg8KB2Rldl9ldWkY",
"X2V1aRgCIAEoCRIRCgljb25maXJtZWQYAyABKAgSDgoGZl9wb3J0GAQgASgN", "AiABKAkSEQoJY29uZmlybWVkGAMgASgIEg4KBmZfcG9ydBgEIAEoDRIMCgRk",
"EgwKBGRhdGEYBSABKAwSJwoGb2JqZWN0GAYgASgLMhcuZ29vZ2xlLnByb3Rv", "YXRhGAUgASgMEicKBm9iamVjdBgGIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5T",
"YnVmLlN0cnVjdCosCghMb2dMZXZlbBIICgRJTkZPEAASCwoHV0FSTklORxAB", "dHJ1Y3QqLAoITG9nTGV2ZWwSCAoESU5GTxAAEgsKB1dBUk5JTkcQARIJCgVF",
"EgkKBUVSUk9SEAIq6gEKB0xvZ0NvZGUSCwoHVU5LTk9XThAAEhkKFURPV05M", "UlJPUhACKuoBCgdMb2dDb2RlEgsKB1VOS05PV04QABIZChVET1dOTElOS19Q",
"SU5LX1BBWUxPQURfU0laRRABEhAKDFVQTElOS19DT0RFQxACEhIKDkRPV05M", "QVlMT0FEX1NJWkUQARIQCgxVUExJTktfQ09ERUMQAhISCg5ET1dOTElOS19D",
"SU5LX0NPREVDEAMSCAoET1RBQRAEEhYKElVQTElOS19GX0NOVF9SRVNFVBAF", "T0RFQxADEggKBE9UQUEQBBIWChJVUExJTktfRl9DTlRfUkVTRVQQBRIOCgpV",
"Eg4KClVQTElOS19NSUMQBhIfChtVUExJTktfRl9DTlRfUkVUUkFOU01JU1NJ", "UExJTktfTUlDEAYSHwobVVBMSU5LX0ZfQ05UX1JFVFJBTlNNSVNTSU9OEAcS",
"T04QBxIUChBET1dOTElOS19HQVRFV0FZEAgSGAoUUkVMQVlfTkVXX0VORF9E", "FAoQRE9XTkxJTktfR0FURVdBWRAIEhgKFFJFTEFZX05FV19FTkRfREVWSUNF",
"RVZJQ0UQCRIOCgpGX0NOVF9ET1dOEApCgQEKHWlvLmNoaXJwc3RhY2suYXBp", "EAkSDgoKRl9DTlRfRE9XThAKQoEBCh1pby5jaGlycHN0YWNrLmFwaS5pbnRl",
"LmludGVncmF0aW9uQhBJbnRlZ3JhdGlvblByb3RvUAFaM2dpdGh1Yi5jb20v", "Z3JhdGlvbkIQSW50ZWdyYXRpb25Qcm90b1ABWjNnaXRodWIuY29tL2Jyb2Nh",
"YnJvY2Fhci9jaGlycHN0YWNrL2FwaS9nby92NC9pbnRlZ3JhdGlvbqoCFkNo", "YXIvY2hpcnBzdGFjay9hcGkvZ28vdjQvaW50ZWdyYXRpb26qAhZDaGlycHN0",
"aXJwc3RhY2suSW50ZWdyYXRpb25iBnByb3RvMw==")); "YWNrLkludGVncmF0aW9uYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Chirpstack.Common.CommonReflection.Descriptor, global::Chirpstack.Gateway.GwReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, }, new pbr::FileDescriptor[] { global::Chirpstack.Common.CommonReflection.Descriptor, global::Chirpstack.Gateway.GwReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Chirpstack.Integration.LogLevel), typeof(global::Chirpstack.Integration.LogCode), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Chirpstack.Integration.LogLevel), typeof(global::Chirpstack.Integration.LogCode), }, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.DeviceInfo), global::Chirpstack.Integration.DeviceInfo.Parser, new[]{ "TenantId", "TenantName", "ApplicationId", "ApplicationName", "DeviceProfileId", "DeviceProfileName", "DeviceName", "DevEui", "DeviceClassEnabled", "Tags" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.DeviceInfo), global::Chirpstack.Integration.DeviceInfo.Parser, new[]{ "TenantId", "TenantName", "ApplicationId", "ApplicationName", "DeviceProfileId", "DeviceProfileName", "DeviceName", "DevEui", "DeviceClassEnabled", "Tags" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.UplinkRelayRxInfo), global::Chirpstack.Integration.UplinkRelayRxInfo.Parser, new[]{ "DevEui", "Frequency", "Dr", "Snr", "Rssi", "WorChannel" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.UplinkRelayRxInfo), global::Chirpstack.Integration.UplinkRelayRxInfo.Parser, new[]{ "DevEui", "Frequency", "Dr", "Snr", "Rssi", "WorChannel" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.JoinServerContext), global::Chirpstack.Integration.JoinServerContext.Parser, new[]{ "SessionKeyId", "AppSKey" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.UplinkEvent), global::Chirpstack.Integration.UplinkEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "DevAddr", "Adr", "Dr", "FCnt", "FPort", "Confirmed", "Data", "Object", "RxInfo", "TxInfo", "RelayRxInfo", "JoinServerContext" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.UplinkEvent), global::Chirpstack.Integration.UplinkEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "DevAddr", "Adr", "Dr", "FCnt", "FPort", "Confirmed", "Data", "Object", "RxInfo", "TxInfo", "RelayRxInfo", "JoinServerContext" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.JoinEvent), global::Chirpstack.Integration.JoinEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "DevAddr", "RelayRxInfo", "JoinServerContext" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.JoinEvent), global::Chirpstack.Integration.JoinEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "DevAddr", "RelayRxInfo", "JoinServerContext" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.AckEvent), global::Chirpstack.Integration.AckEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "QueueItemId", "Acknowledged", "FCntDown" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Chirpstack.Integration.AckEvent), global::Chirpstack.Integration.AckEvent.Parser, new[]{ "DeduplicationId", "Time", "DeviceInfo", "QueueItemId", "Acknowledged", "FCntDown" }, null, null, null, null),
@ -1124,250 +1121,6 @@ namespace Chirpstack.Integration {
} }
/// <summary>
/// Join-Server context.
/// </summary>
public sealed partial class JoinServerContext : pb::IMessage<JoinServerContext>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<JoinServerContext> _parser = new pb::MessageParser<JoinServerContext>(() => new JoinServerContext());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<JoinServerContext> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[2]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext(JoinServerContext other) : this() {
sessionKeyId_ = other.sessionKeyId_;
appSKey_ = other.appSKey_ != null ? other.appSKey_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public JoinServerContext Clone() {
return new JoinServerContext(this);
}
/// <summary>Field number for the "session_key_id" field.</summary>
public const int SessionKeyIdFieldNumber = 1;
private string sessionKeyId_ = "";
/// <summary>
/// Session-key ID.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string SessionKeyId {
get { return sessionKeyId_; }
set {
sessionKeyId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "app_s_key" field.</summary>
public const int AppSKeyFieldNumber = 2;
private global::Chirpstack.Common.KeyEnvelope appSKey_;
/// <summary>
/// AppSKey envelope.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Chirpstack.Common.KeyEnvelope AppSKey {
get { return appSKey_; }
set {
appSKey_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as JoinServerContext);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(JoinServerContext other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (SessionKeyId != other.SessionKeyId) return false;
if (!object.Equals(AppSKey, other.AppSKey)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (SessionKeyId.Length != 0) hash ^= SessionKeyId.GetHashCode();
if (appSKey_ != null) hash ^= AppSKey.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (SessionKeyId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(SessionKeyId);
}
if (appSKey_ != null) {
output.WriteRawTag(18);
output.WriteMessage(AppSKey);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (SessionKeyId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(SessionKeyId);
}
if (appSKey_ != null) {
output.WriteRawTag(18);
output.WriteMessage(AppSKey);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (SessionKeyId.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(SessionKeyId);
}
if (appSKey_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(AppSKey);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(JoinServerContext other) {
if (other == null) {
return;
}
if (other.SessionKeyId.Length != 0) {
SessionKeyId = other.SessionKeyId;
}
if (other.appSKey_ != null) {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
AppSKey.MergeFrom(other.AppSKey);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
SessionKeyId = input.ReadString();
break;
}
case 18: {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
input.ReadMessage(AppSKey);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
SessionKeyId = input.ReadString();
break;
}
case 18: {
if (appSKey_ == null) {
AppSKey = new global::Chirpstack.Common.KeyEnvelope();
}
input.ReadMessage(AppSKey);
break;
}
}
}
}
#endif
}
/// <summary> /// <summary>
/// UplinkEvent is the message sent when an uplink payload has been received. /// UplinkEvent is the message sent when an uplink payload has been received.
/// </summary> /// </summary>
@ -1385,7 +1138,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[3]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[2]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -1641,7 +1394,7 @@ namespace Chirpstack.Integration {
/// <summary>Field number for the "join_server_context" field.</summary> /// <summary>Field number for the "join_server_context" field.</summary>
public const int JoinServerContextFieldNumber = 15; public const int JoinServerContextFieldNumber = 15;
private global::Chirpstack.Integration.JoinServerContext joinServerContext_; private global::Chirpstack.Common.JoinServerContext joinServerContext_;
/// <summary> /// <summary>
/// Join-Server context. /// Join-Server context.
/// A non-empty value indicatest that ChirpStack does not have access to /// A non-empty value indicatest that ChirpStack does not have access to
@ -1650,7 +1403,7 @@ namespace Chirpstack.Integration {
/// </summary> /// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Chirpstack.Integration.JoinServerContext JoinServerContext { public global::Chirpstack.Common.JoinServerContext JoinServerContext {
get { return joinServerContext_; } get { return joinServerContext_; }
set { set {
joinServerContext_ = value; joinServerContext_ = value;
@ -1973,7 +1726,7 @@ namespace Chirpstack.Integration {
} }
if (other.joinServerContext_ != null) { if (other.joinServerContext_ != null) {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
JoinServerContext.MergeFrom(other.JoinServerContext); JoinServerContext.MergeFrom(other.JoinServerContext);
} }
@ -2065,7 +1818,7 @@ namespace Chirpstack.Integration {
} }
case 122: { case 122: {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
input.ReadMessage(JoinServerContext); input.ReadMessage(JoinServerContext);
break; break;
@ -2158,7 +1911,7 @@ namespace Chirpstack.Integration {
} }
case 122: { case 122: {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
input.ReadMessage(JoinServerContext); input.ReadMessage(JoinServerContext);
break; break;
@ -2188,7 +1941,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[4]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[3]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -2300,7 +2053,7 @@ namespace Chirpstack.Integration {
/// <summary>Field number for the "join_server_context" field.</summary> /// <summary>Field number for the "join_server_context" field.</summary>
public const int JoinServerContextFieldNumber = 6; public const int JoinServerContextFieldNumber = 6;
private global::Chirpstack.Integration.JoinServerContext joinServerContext_; private global::Chirpstack.Common.JoinServerContext joinServerContext_;
/// <summary> /// <summary>
/// Join-Server context. /// Join-Server context.
/// A non-empty value indicatest that ChirpStack does not have access to /// A non-empty value indicatest that ChirpStack does not have access to
@ -2309,7 +2062,7 @@ namespace Chirpstack.Integration {
/// </summary> /// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Chirpstack.Integration.JoinServerContext JoinServerContext { public global::Chirpstack.Common.JoinServerContext JoinServerContext {
get { return joinServerContext_; } get { return joinServerContext_; }
set { set {
joinServerContext_ = value; joinServerContext_ = value;
@ -2492,7 +2245,7 @@ namespace Chirpstack.Integration {
} }
if (other.joinServerContext_ != null) { if (other.joinServerContext_ != null) {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
JoinServerContext.MergeFrom(other.JoinServerContext); JoinServerContext.MergeFrom(other.JoinServerContext);
} }
@ -2542,7 +2295,7 @@ namespace Chirpstack.Integration {
} }
case 50: { case 50: {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
input.ReadMessage(JoinServerContext); input.ReadMessage(JoinServerContext);
break; break;
@ -2593,7 +2346,7 @@ namespace Chirpstack.Integration {
} }
case 50: { case 50: {
if (joinServerContext_ == null) { if (joinServerContext_ == null) {
JoinServerContext = new global::Chirpstack.Integration.JoinServerContext(); JoinServerContext = new global::Chirpstack.Common.JoinServerContext();
} }
input.ReadMessage(JoinServerContext); input.ReadMessage(JoinServerContext);
break; break;
@ -2623,7 +2376,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[5]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[4]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -3038,7 +2791,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[6]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[5]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -3500,7 +3253,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[7]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[6]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -3903,7 +3656,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[8]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[7]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -4357,7 +4110,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[9]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[8]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -4701,7 +4454,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[10]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[9]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -5124,7 +4877,7 @@ namespace Chirpstack.Integration {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[11]; } get { return global::Chirpstack.Integration.IntegrationReflection.Descriptor.MessageTypes[10]; }
} }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.Diagnostics.DebuggerNonUserCodeAttribute]

View File

@ -1375,6 +1375,11 @@ type GetDeviceActivationResponse struct {
// Device activation object. // Device activation object.
DeviceActivation *DeviceActivation `protobuf:"bytes,1,opt,name=device_activation,json=deviceActivation,proto3" json:"device_activation,omitempty"` DeviceActivation *DeviceActivation `protobuf:"bytes,1,opt,name=device_activation,json=deviceActivation,proto3" json:"device_activation,omitempty"`
// Join-Server context.
// A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application.
JoinServerContext *common.JoinServerContext `protobuf:"bytes,2,opt,name=join_server_context,json=joinServerContext,proto3" json:"join_server_context,omitempty"`
} }
func (x *GetDeviceActivationResponse) Reset() { func (x *GetDeviceActivationResponse) Reset() {
@ -1416,6 +1421,13 @@ func (x *GetDeviceActivationResponse) GetDeviceActivation() *DeviceActivation {
return nil return nil
} }
func (x *GetDeviceActivationResponse) GetJoinServerContext() *common.JoinServerContext {
if x != nil {
return x.JoinServerContext
}
return nil
}
type GetRandomDevAddrRequest struct { type GetRandomDevAddrRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -2594,291 +2606,295 @@ var file_api_device_proto_rawDesc = []byte{
0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x35, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x35, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x61, 0x0a, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0xac, 0x01,
0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x11, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f,
0x22, 0x32, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x6e, 0x12, 0x49, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76,
0x76, 0x45, 0x75, 0x69, 0x22, 0x35, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x53,
0x6d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x32, 0x0a, 0x17,
0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72,
0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x22, 0xc9, 0x01, 0x0a, 0x17,
0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65,
0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69,
0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x35, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x22, 0xc9, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x44,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01,
0x12, 0x35, 0x0a, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x30, 0x0a, 0x05,
0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xbc, 0x02, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c,
0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x35, 0x0a, 0x0b,
0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x0e, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65,
0x79, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x41, 0x0a, 0x06, 0x73, 0x74, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74,
0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x70, 0x69, 0x69, 0x6f, 0x6e, 0x22, 0xbc, 0x02, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x4a, 0x0a, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d,
0x24, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x41, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x05, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73,
0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x79, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x4a, 0x0a, 0x0c, 0x4d, 0x65, 0x74,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x37, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d,
0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x45,
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0xcd, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69,
0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x38, 0x01, 0x22, 0x37, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,
0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x1b,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64,
0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x61, 0x67, 0x67, 0x72,
0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
0xbf, 0x02, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e,
0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x2d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x52, 0x09, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12,
0x27, 0x0a, 0x07, 0x67, 0x77, 0x5f, 0x72, 0x73, 0x73, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x52, 0x06, 0x67, 0x77, 0x52, 0x73, 0x73, 0x69, 0x12, 0x25, 0x0a, 0x06, 0x67, 0x77, 0x5f, 0x73,
0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x05, 0x67, 0x77, 0x53, 0x6e, 0x72, 0x12,
0x3d, 0x0a, 0x13, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x65,
0x72, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x10, 0x72, 0x78,
0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x50, 0x65, 0x72, 0x46, 0x72, 0x65, 0x71, 0x12, 0x39,
0x0a, 0x11, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x65, 0x72,
0x5f, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0e, 0x72, 0x78, 0x50, 0x61, 0x63,
0x6b, 0x65, 0x74, 0x73, 0x50, 0x65, 0x72, 0x44, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x73, 0x22, 0x94, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75,
0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x1c,
0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x15, 0x0a, 0x06,
0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x50,
0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74,
0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x70,
0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73,
0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74,
0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e,
0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x65, 0x6e, 0x63, 0x72,
0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x45,
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0x54, 0x0a, 0x1d, 0x45, 0x6e, 0x71, 0x75,
0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74,
0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x71, 0x75, 0x65,
0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49,
0x74, 0x65, 0x6d, 0x52, 0x09, 0x71, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x30,
0x0a, 0x1e, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51,
0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x22, 0x32, 0x0a, 0x17, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51,
0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64,
0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65,
0x76, 0x45, 0x75, 0x69, 0x22, 0x54, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x76, 0x45, 0x75, 0x69, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20,
0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20,
0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x6c, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6f, 0x6e, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b,
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xbf, 0x02, 0x0a, 0x1c,
0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x74,
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x0a,
0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x30, 0x0a, 0x15, 0x46, 0x6c, 0x75, 0x73, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x68, 0x44, 0x65, 0x76, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x52, 0x09, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x07, 0x67,
0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x37, 0x0a, 0x1c, 0x47, 0x65, 0x77, 0x5f, 0x72, 0x73, 0x73, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x06, 0x67, 0x77,
0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x52, 0x73, 0x73, 0x69, 0x12, 0x25, 0x0a, 0x06, 0x67, 0x77, 0x5f, 0x73, 0x6e, 0x72, 0x18, 0x03,
0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65,
0x45, 0x75, 0x69, 0x22, 0x3d, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x05, 0x67, 0x77, 0x53, 0x6e, 0x72, 0x12, 0x3d, 0x0a, 0x13, 0x72,
0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x72,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x65, 0x71, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x77, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x10, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b,
0x77, 0x6e, 0x32, 0xe2, 0x11, 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x72, 0x65, 0x74, 0x73, 0x50, 0x65, 0x72, 0x46, 0x72, 0x65, 0x71, 0x12, 0x39, 0x0a, 0x11, 0x72, 0x78,
0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x18, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x72, 0x18,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0e, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x50, 0x65, 0x72, 0x44, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18,
0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d,
0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x94, 0x02,
0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x02, 0x20, 0x01,
0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x12, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63,
0x64, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12,
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20,
0x93, 0x02, 0x22, 0x3a, 0x01, 0x2a, 0x1a, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62,
0x5f, 0x65, 0x75, 0x69, 0x7d, 0x12, 0x5a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69,
0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50, 0x65, 0x6e, 0x64,
0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77,
0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77,
0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x45, 0x6e, 0x63, 0x72, 0x79,
0x70, 0x74, 0x65, 0x64, 0x22, 0x54, 0x0a, 0x1d, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69,
0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52,
0x09, 0x71, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x30, 0x0a, 0x1e, 0x45, 0x6e,
0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65,
0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x32, 0x0a, 0x17,
0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65,
0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69,
0x22, 0x54, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65,
0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17,
0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x6c, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x22, 0x30, 0x0a, 0x15, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76,
0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a,
0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x37, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75,
0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22,
0x3d, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74,
0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x32, 0xe2,
0x11, 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x53, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x17, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x12, 0x64, 0x0a, 0x06, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x3a,
0x01, 0x2a, 0x1a, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69,
0x7d, 0x12, 0x5a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1e, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x12, 0x4f, 0x0a,
0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e,
0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x76,
0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1c, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4b,
0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69,
0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x65, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79,
0x73, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d,
0x12, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b,
0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x76, 0x0a,
0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65,
0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x1a, 0x27, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d,
0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x67, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b,
0x65, 0x79, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x1d, 0x2a, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x6f,
0x0a, 0x0e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73,
0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x4e,
0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x2a, 0x21, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f,
0x65, 0x75, 0x69, 0x7d, 0x2f, 0x64, 0x65, 0x76, 0x2d, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12,
0x7c, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x3a, 0x01, 0x2a, 0x22, 0x31, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x5f,
0x65, 0x75, 0x69, 0x7d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x6d, 0x0a,
0x0a, 0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x79, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x2a, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69,
0x7d, 0x12, 0x4f, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x7d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7d, 0x0a, 0x0d,
0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e,
0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x74,
0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63,
0x65, 0x73, 0x12, 0x76, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x12, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64,
0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01,
0x2a, 0x22, 0x27, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x64, 0x65, 0x76,
0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x65, 0x0a, 0x07, 0x47, 0x65,
0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65, 0x79,
0x73, 0x12, 0x76, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12,
0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a,
0x1a, 0x27, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x64, 0x65, 0x76, 0x5f,
0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x67, 0x0a, 0x0a, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x23, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6b, 0x65,
0x79, 0x73, 0x12, 0x6f, 0x0a, 0x0e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x4e, 0x6f,
0x6e, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x6c, 0x75, 0x73, 0x68,
0x44, 0x65, 0x76, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23,
0x2a, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b,
0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x64, 0x65, 0x76, 0x2d, 0x6e, 0x6f, 0x6e,
0x63, 0x65, 0x73, 0x12, 0x7c, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12,
0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x3a, 0x01, 0x2a, 0x22, 0x31,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
0x65, 0x12, 0x6d, 0x0a, 0x0a, 0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12,
0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x2a, 0x21, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76,
0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x7d, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x12, 0x21, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f,
0x65, 0x75, 0x69, 0x7d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x83, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76,
0x41, 0x64, 0x64, 0x72, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61,
0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64,
0x6f, 0x6d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x2a, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69,
0x7d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x2d, 0x64, 0x65, 0x76,
0x2d, 0x61, 0x64, 0x64, 0x72, 0x12, 0x71, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72,
0x69, 0x63, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d,
0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x83, 0x01, 0x0a, 0x10,
0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72,
0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d,
0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x44, 0x65,
0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82,
0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x2a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69,
0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x67, 0x65,
0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x86, 0x01, 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x2d, 0x64, 0x65, 0x76, 0x2d, 0x61, 0x64, 0x64,
0x0a, 0x07, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x12, 0x71, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d,
0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x6e, 0x6b,
0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69,
0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x6c, 0x69, 0x6e,
0x6b, 0x2d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x86, 0x01, 0x0a, 0x07, 0x45, 0x6e,
0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6e, 0x71, 0x75,
0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74,
0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65,
0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32,
0x61, 0x70, 0x69, 0x2e, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69,
0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, 0x2f, 0x74, 0x65, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x71, 0x75, 0x65,
0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x68, 0x0a, 0x0a, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x51, 0x75, 0x65, 0x75, 0x65,
0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x44, 0x65, 0x76, 0x69,
0x2f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x68, 0x0a, 0x0a, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x51, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
0x75, 0x65, 0x75, 0x65, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x2a, 0x1c,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x73, 0x0a, 0x08,
0x02, 0x1e, 0x2a, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65,
0x12, 0x73, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74,
0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4,
0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x75,
0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65, 0x65, 0x12, 0x8f, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e,
0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74,
0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, 0x22, 0x2a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x7d, 0x2f,
0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x8f, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x78, 0x67, 0x65, 0x74, 0x2d, 0x6e, 0x65, 0x78, 0x74, 0x2d, 0x66, 0x2d, 0x63, 0x6e, 0x74, 0x2d, 0x64,
0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x6f, 0x77, 0x6e, 0x42, 0x63, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73,
0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x63,
0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f,
0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, 0x22, 0x2a, 0x2f, 0x61, 0x70, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x69, 0xaa, 0x02, 0x0e, 0x43, 0x68, 0x69, 0x72, 0x70, 0x73,
0x69, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x75, 0x69, 0x7d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x6e, 0x65, 0x78, 0x74, 0x2d, 0x66, 0x2d, 0x63,
0x6e, 0x74, 0x2d, 0x64, 0x6f, 0x77, 0x6e, 0x42, 0x63, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x63, 0x68,
0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61,
0x63, 0x6b, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x69, 0xaa, 0x02, 0x0e, 0x43, 0x68,
0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -2938,10 +2954,11 @@ var file_api_device_proto_goTypes = []interface{}{
nil, // 40: api.GetDeviceMetricsResponse.StatesEntry nil, // 40: api.GetDeviceMetricsResponse.StatesEntry
(*timestamppb.Timestamp)(nil), // 41: google.protobuf.Timestamp (*timestamppb.Timestamp)(nil), // 41: google.protobuf.Timestamp
(common.DeviceClass)(0), // 42: common.DeviceClass (common.DeviceClass)(0), // 42: common.DeviceClass
(common.Aggregation)(0), // 43: common.Aggregation (*common.JoinServerContext)(nil), // 43: common.JoinServerContext
(*common.Metric)(nil), // 44: common.Metric (common.Aggregation)(0), // 44: common.Aggregation
(*structpb.Struct)(nil), // 45: google.protobuf.Struct (*common.Metric)(nil), // 45: common.Metric
(*emptypb.Empty)(nil), // 46: google.protobuf.Empty (*structpb.Struct)(nil), // 46: google.protobuf.Struct
(*emptypb.Empty)(nil), // 47: google.protobuf.Empty
} }
var file_api_device_proto_depIdxs = []int32{ var file_api_device_proto_depIdxs = []int32{
37, // 0: api.Device.variables:type_name -> api.Device.VariablesEntry 37, // 0: api.Device.variables:type_name -> api.Device.VariablesEntry
@ -2966,70 +2983,71 @@ var file_api_device_proto_depIdxs = []int32{
3, // 19: api.UpdateDeviceKeysRequest.device_keys:type_name -> api.DeviceKeys 3, // 19: api.UpdateDeviceKeysRequest.device_keys:type_name -> api.DeviceKeys
16, // 20: api.ActivateDeviceRequest.device_activation:type_name -> api.DeviceActivation 16, // 20: api.ActivateDeviceRequest.device_activation:type_name -> api.DeviceActivation
16, // 21: api.GetDeviceActivationResponse.device_activation:type_name -> api.DeviceActivation 16, // 21: api.GetDeviceActivationResponse.device_activation:type_name -> api.DeviceActivation
41, // 22: api.GetDeviceMetricsRequest.start:type_name -> google.protobuf.Timestamp 43, // 22: api.GetDeviceActivationResponse.join_server_context:type_name -> common.JoinServerContext
41, // 23: api.GetDeviceMetricsRequest.end:type_name -> google.protobuf.Timestamp 41, // 23: api.GetDeviceMetricsRequest.start:type_name -> google.protobuf.Timestamp
43, // 24: api.GetDeviceMetricsRequest.aggregation:type_name -> common.Aggregation 41, // 24: api.GetDeviceMetricsRequest.end:type_name -> google.protobuf.Timestamp
39, // 25: api.GetDeviceMetricsResponse.metrics:type_name -> api.GetDeviceMetricsResponse.MetricsEntry 44, // 25: api.GetDeviceMetricsRequest.aggregation:type_name -> common.Aggregation
40, // 26: api.GetDeviceMetricsResponse.states:type_name -> api.GetDeviceMetricsResponse.StatesEntry 39, // 26: api.GetDeviceMetricsResponse.metrics:type_name -> api.GetDeviceMetricsResponse.MetricsEntry
41, // 27: api.GetDeviceLinkMetricsRequest.start:type_name -> google.protobuf.Timestamp 40, // 27: api.GetDeviceMetricsResponse.states:type_name -> api.GetDeviceMetricsResponse.StatesEntry
41, // 28: api.GetDeviceLinkMetricsRequest.end:type_name -> google.protobuf.Timestamp 41, // 28: api.GetDeviceLinkMetricsRequest.start:type_name -> google.protobuf.Timestamp
43, // 29: api.GetDeviceLinkMetricsRequest.aggregation:type_name -> common.Aggregation 41, // 29: api.GetDeviceLinkMetricsRequest.end:type_name -> google.protobuf.Timestamp
44, // 30: api.GetDeviceLinkMetricsResponse.rx_packets:type_name -> common.Metric 44, // 30: api.GetDeviceLinkMetricsRequest.aggregation:type_name -> common.Aggregation
44, // 31: api.GetDeviceLinkMetricsResponse.gw_rssi:type_name -> common.Metric 45, // 31: api.GetDeviceLinkMetricsResponse.rx_packets:type_name -> common.Metric
44, // 32: api.GetDeviceLinkMetricsResponse.gw_snr:type_name -> common.Metric 45, // 32: api.GetDeviceLinkMetricsResponse.gw_rssi:type_name -> common.Metric
44, // 33: api.GetDeviceLinkMetricsResponse.rx_packets_per_freq:type_name -> common.Metric 45, // 33: api.GetDeviceLinkMetricsResponse.gw_snr:type_name -> common.Metric
44, // 34: api.GetDeviceLinkMetricsResponse.rx_packets_per_dr:type_name -> common.Metric 45, // 34: api.GetDeviceLinkMetricsResponse.rx_packets_per_freq:type_name -> common.Metric
44, // 35: api.GetDeviceLinkMetricsResponse.errors:type_name -> common.Metric 45, // 35: api.GetDeviceLinkMetricsResponse.rx_packets_per_dr:type_name -> common.Metric
45, // 36: api.DeviceQueueItem.object:type_name -> google.protobuf.Struct 45, // 36: api.GetDeviceLinkMetricsResponse.errors:type_name -> common.Metric
28, // 37: api.EnqueueDeviceQueueItemRequest.queue_item:type_name -> api.DeviceQueueItem 46, // 37: api.DeviceQueueItem.object:type_name -> google.protobuf.Struct
28, // 38: api.GetDeviceQueueItemsResponse.result:type_name -> api.DeviceQueueItem 28, // 38: api.EnqueueDeviceQueueItemRequest.queue_item:type_name -> api.DeviceQueueItem
44, // 39: api.GetDeviceMetricsResponse.MetricsEntry.value:type_name -> common.Metric 28, // 39: api.GetDeviceQueueItemsResponse.result:type_name -> api.DeviceQueueItem
25, // 40: api.GetDeviceMetricsResponse.StatesEntry.value:type_name -> api.DeviceState 45, // 40: api.GetDeviceMetricsResponse.MetricsEntry.value:type_name -> common.Metric
4, // 41: api.DeviceService.Create:input_type -> api.CreateDeviceRequest 25, // 41: api.GetDeviceMetricsResponse.StatesEntry.value:type_name -> api.DeviceState
5, // 42: api.DeviceService.Get:input_type -> api.GetDeviceRequest 4, // 42: api.DeviceService.Create:input_type -> api.CreateDeviceRequest
7, // 43: api.DeviceService.Update:input_type -> api.UpdateDeviceRequest 5, // 43: api.DeviceService.Get:input_type -> api.GetDeviceRequest
8, // 44: api.DeviceService.Delete:input_type -> api.DeleteDeviceRequest 7, // 44: api.DeviceService.Update:input_type -> api.UpdateDeviceRequest
9, // 45: api.DeviceService.List:input_type -> api.ListDevicesRequest 8, // 45: api.DeviceService.Delete:input_type -> api.DeleteDeviceRequest
11, // 46: api.DeviceService.CreateKeys:input_type -> api.CreateDeviceKeysRequest 9, // 46: api.DeviceService.List:input_type -> api.ListDevicesRequest
12, // 47: api.DeviceService.GetKeys:input_type -> api.GetDeviceKeysRequest 11, // 47: api.DeviceService.CreateKeys:input_type -> api.CreateDeviceKeysRequest
14, // 48: api.DeviceService.UpdateKeys:input_type -> api.UpdateDeviceKeysRequest 12, // 48: api.DeviceService.GetKeys:input_type -> api.GetDeviceKeysRequest
15, // 49: api.DeviceService.DeleteKeys:input_type -> api.DeleteDeviceKeysRequest 14, // 49: api.DeviceService.UpdateKeys:input_type -> api.UpdateDeviceKeysRequest
34, // 50: api.DeviceService.FlushDevNonces:input_type -> api.FlushDevNoncesRequest 15, // 50: api.DeviceService.DeleteKeys:input_type -> api.DeleteDeviceKeysRequest
17, // 51: api.DeviceService.Activate:input_type -> api.ActivateDeviceRequest 34, // 51: api.DeviceService.FlushDevNonces:input_type -> api.FlushDevNoncesRequest
18, // 52: api.DeviceService.Deactivate:input_type -> api.DeactivateDeviceRequest 17, // 52: api.DeviceService.Activate:input_type -> api.ActivateDeviceRequest
19, // 53: api.DeviceService.GetActivation:input_type -> api.GetDeviceActivationRequest 18, // 53: api.DeviceService.Deactivate:input_type -> api.DeactivateDeviceRequest
21, // 54: api.DeviceService.GetRandomDevAddr:input_type -> api.GetRandomDevAddrRequest 19, // 54: api.DeviceService.GetActivation:input_type -> api.GetDeviceActivationRequest
23, // 55: api.DeviceService.GetMetrics:input_type -> api.GetDeviceMetricsRequest 21, // 55: api.DeviceService.GetRandomDevAddr:input_type -> api.GetRandomDevAddrRequest
26, // 56: api.DeviceService.GetLinkMetrics:input_type -> api.GetDeviceLinkMetricsRequest 23, // 56: api.DeviceService.GetMetrics:input_type -> api.GetDeviceMetricsRequest
29, // 57: api.DeviceService.Enqueue:input_type -> api.EnqueueDeviceQueueItemRequest 26, // 57: api.DeviceService.GetLinkMetrics:input_type -> api.GetDeviceLinkMetricsRequest
31, // 58: api.DeviceService.FlushQueue:input_type -> api.FlushDeviceQueueRequest 29, // 58: api.DeviceService.Enqueue:input_type -> api.EnqueueDeviceQueueItemRequest
32, // 59: api.DeviceService.GetQueue:input_type -> api.GetDeviceQueueItemsRequest 31, // 59: api.DeviceService.FlushQueue:input_type -> api.FlushDeviceQueueRequest
35, // 60: api.DeviceService.GetNextFCntDown:input_type -> api.GetDeviceNextFCntDownRequest 32, // 60: api.DeviceService.GetQueue:input_type -> api.GetDeviceQueueItemsRequest
46, // 61: api.DeviceService.Create:output_type -> google.protobuf.Empty 35, // 61: api.DeviceService.GetNextFCntDown:input_type -> api.GetDeviceNextFCntDownRequest
6, // 62: api.DeviceService.Get:output_type -> api.GetDeviceResponse 47, // 62: api.DeviceService.Create:output_type -> google.protobuf.Empty
46, // 63: api.DeviceService.Update:output_type -> google.protobuf.Empty 6, // 63: api.DeviceService.Get:output_type -> api.GetDeviceResponse
46, // 64: api.DeviceService.Delete:output_type -> google.protobuf.Empty 47, // 64: api.DeviceService.Update:output_type -> google.protobuf.Empty
10, // 65: api.DeviceService.List:output_type -> api.ListDevicesResponse 47, // 65: api.DeviceService.Delete:output_type -> google.protobuf.Empty
46, // 66: api.DeviceService.CreateKeys:output_type -> google.protobuf.Empty 10, // 66: api.DeviceService.List:output_type -> api.ListDevicesResponse
13, // 67: api.DeviceService.GetKeys:output_type -> api.GetDeviceKeysResponse 47, // 67: api.DeviceService.CreateKeys:output_type -> google.protobuf.Empty
46, // 68: api.DeviceService.UpdateKeys:output_type -> google.protobuf.Empty 13, // 68: api.DeviceService.GetKeys:output_type -> api.GetDeviceKeysResponse
46, // 69: api.DeviceService.DeleteKeys:output_type -> google.protobuf.Empty 47, // 69: api.DeviceService.UpdateKeys:output_type -> google.protobuf.Empty
46, // 70: api.DeviceService.FlushDevNonces:output_type -> google.protobuf.Empty 47, // 70: api.DeviceService.DeleteKeys:output_type -> google.protobuf.Empty
46, // 71: api.DeviceService.Activate:output_type -> google.protobuf.Empty 47, // 71: api.DeviceService.FlushDevNonces:output_type -> google.protobuf.Empty
46, // 72: api.DeviceService.Deactivate:output_type -> google.protobuf.Empty 47, // 72: api.DeviceService.Activate:output_type -> google.protobuf.Empty
20, // 73: api.DeviceService.GetActivation:output_type -> api.GetDeviceActivationResponse 47, // 73: api.DeviceService.Deactivate:output_type -> google.protobuf.Empty
22, // 74: api.DeviceService.GetRandomDevAddr:output_type -> api.GetRandomDevAddrResponse 20, // 74: api.DeviceService.GetActivation:output_type -> api.GetDeviceActivationResponse
24, // 75: api.DeviceService.GetMetrics:output_type -> api.GetDeviceMetricsResponse 22, // 75: api.DeviceService.GetRandomDevAddr:output_type -> api.GetRandomDevAddrResponse
27, // 76: api.DeviceService.GetLinkMetrics:output_type -> api.GetDeviceLinkMetricsResponse 24, // 76: api.DeviceService.GetMetrics:output_type -> api.GetDeviceMetricsResponse
30, // 77: api.DeviceService.Enqueue:output_type -> api.EnqueueDeviceQueueItemResponse 27, // 77: api.DeviceService.GetLinkMetrics:output_type -> api.GetDeviceLinkMetricsResponse
46, // 78: api.DeviceService.FlushQueue:output_type -> google.protobuf.Empty 30, // 78: api.DeviceService.Enqueue:output_type -> api.EnqueueDeviceQueueItemResponse
33, // 79: api.DeviceService.GetQueue:output_type -> api.GetDeviceQueueItemsResponse 47, // 79: api.DeviceService.FlushQueue:output_type -> google.protobuf.Empty
36, // 80: api.DeviceService.GetNextFCntDown:output_type -> api.GetDeviceNextFCntDownResponse 33, // 80: api.DeviceService.GetQueue:output_type -> api.GetDeviceQueueItemsResponse
61, // [61:81] is the sub-list for method output_type 36, // 81: api.DeviceService.GetNextFCntDown:output_type -> api.GetDeviceNextFCntDownResponse
41, // [41:61] is the sub-list for method input_type 62, // [62:82] is the sub-list for method output_type
41, // [41:41] is the sub-list for extension type_name 42, // [42:62] is the sub-list for method input_type
41, // [41:41] is the sub-list for extension extendee 42, // [42:42] is the sub-list for extension type_name
0, // [0:41] is the sub-list for field type_name 42, // [42:42] is the sub-list for extension extendee
0, // [0:42] is the sub-list for field type_name
} }
func init() { file_api_device_proto_init() } func init() { file_api_device_proto_init() }

View File

@ -856,6 +856,64 @@ func (x *MetricDataset) GetData() []float32 {
return nil return nil
} }
// Join-Server context.
type JoinServerContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Session-key ID.
SessionKeyId string `protobuf:"bytes,1,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"`
// AppSKey envelope.
AppSKey *KeyEnvelope `protobuf:"bytes,2,opt,name=app_s_key,json=appSKey,proto3" json:"app_s_key,omitempty"`
}
func (x *JoinServerContext) Reset() {
*x = JoinServerContext{}
if protoimpl.UnsafeEnabled {
mi := &file_common_common_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *JoinServerContext) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*JoinServerContext) ProtoMessage() {}
func (x *JoinServerContext) ProtoReflect() protoreflect.Message {
mi := &file_common_common_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use JoinServerContext.ProtoReflect.Descriptor instead.
func (*JoinServerContext) Descriptor() ([]byte, []int) {
return file_common_common_proto_rawDescGZIP(), []int{4}
}
func (x *JoinServerContext) GetSessionKeyId() string {
if x != nil {
return x.SessionKeyId
}
return ""
}
func (x *JoinServerContext) GetAppSKey() *KeyEnvelope {
if x != nil {
return x.AppSKey
}
return nil
}
var File_common_common_proto protoreflect.FileDescriptor var File_common_common_proto protoreflect.FileDescriptor
var file_common_common_proto_rawDesc = []byte{ var file_common_common_proto_rawDesc = []byte{
@ -893,72 +951,79 @@ var file_common_common_proto_rawDesc = []byte{
0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62,
0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12,
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x02, 0x52, 0x04, 0x64, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x02, 0x52, 0x04, 0x64,
0x61, 0x74, 0x61, 0x2a, 0x2c, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x61, 0x74, 0x61, 0x22, 0x6a, 0x0a, 0x11, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65,
0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x52, 0x41, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73,
0x53, 0x4b, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x52, 0x5f, 0x46, 0x48, 0x53, 0x53, 0x10, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x02, 0x2a, 0xaa, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x2f,
0x45, 0x55, 0x38, 0x36, 0x38, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x53, 0x39, 0x31, 0x35, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4e, 0x37, 0x37, 0x39, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x45, 0x6e,
0x05, 0x45, 0x55, 0x34, 0x33, 0x33, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x39, 0x31, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x61, 0x70, 0x70, 0x53, 0x4b, 0x65, 0x79, 0x2a,
0x35, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4e, 0x34, 0x37, 0x30, 0x10, 0x06, 0x12, 0x09, 0x2c, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a,
0x0a, 0x05, 0x41, 0x53, 0x39, 0x32, 0x33, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x04, 0x4c, 0x4f, 0x52, 0x41, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x53, 0x4b, 0x10, 0x01,
0x32, 0x33, 0x5f, 0x32, 0x10, 0x0c, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x32, 0x33, 0x5f, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x52, 0x5f, 0x46, 0x48, 0x53, 0x53, 0x10, 0x02, 0x2a, 0xaa, 0x01,
0x33, 0x10, 0x0d, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x32, 0x33, 0x5f, 0x34, 0x10, 0x0e, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x55, 0x38, 0x36,
0x12, 0x09, 0x0a, 0x05, 0x4b, 0x52, 0x39, 0x32, 0x30, 0x10, 0x08, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x38, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x53, 0x39, 0x31, 0x35, 0x10, 0x02, 0x12, 0x09,
0x4e, 0x38, 0x36, 0x35, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x55, 0x38, 0x36, 0x34, 0x10, 0x0a, 0x05, 0x43, 0x4e, 0x37, 0x37, 0x39, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x55, 0x34,
0x0a, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x53, 0x4d, 0x32, 0x34, 0x30, 0x30, 0x10, 0x0b, 0x2a, 0xb3, 0x33, 0x33, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x39, 0x31, 0x35, 0x10, 0x05, 0x12,
0x01, 0x0a, 0x05, 0x4d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4a, 0x4f, 0x49, 0x4e, 0x09, 0x0a, 0x05, 0x43, 0x4e, 0x34, 0x37, 0x30, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53,
0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4a, 0x4f, 0x39, 0x32, 0x33, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x32, 0x33, 0x5f, 0x32,
0x49, 0x4e, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x10, 0x0c, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x32, 0x33, 0x5f, 0x33, 0x10, 0x0d, 0x12,
0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x0b, 0x0a, 0x07, 0x41, 0x53, 0x39, 0x32, 0x33, 0x5f, 0x34, 0x10, 0x0e, 0x12, 0x09, 0x0a, 0x05,
0x55, 0x50, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4b, 0x52, 0x39, 0x32, 0x30, 0x10, 0x08, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x38, 0x36, 0x35,
0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x55, 0x38, 0x36, 0x34, 0x10, 0x0a, 0x12, 0x0b, 0x0a,
0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x07, 0x49, 0x53, 0x4d, 0x32, 0x34, 0x30, 0x30, 0x10, 0x0b, 0x2a, 0xb3, 0x01, 0x0a, 0x05, 0x4d,
0x41, 0x5f, 0x55, 0x50, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51,
0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x05, 0x12, 0x55, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x41,
0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x43, 0x4f, 0x4e,
0x54, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x50, 0x52, 0x49, 0x45, 0x54, 0x41, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, 0x10, 0x02,
0x52, 0x59, 0x10, 0x07, 0x2a, 0x7e, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f,
0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x43,
0x30, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50,
0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f,
0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x52,
0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x11, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x06, 0x12,
0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x34, 0x10, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x50, 0x52, 0x49, 0x45, 0x54, 0x41, 0x52, 0x59, 0x10, 0x07,
0x04, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x31, 0x2a, 0x7e, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x11,
0x5f, 0x30, 0x10, 0x05, 0x2a, 0x65, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x10,
0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x00, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30,
0x12, 0x05, 0x0a, 0x01, 0x42, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f,
0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57,
0x32, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f,
0x30, 0x32, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x11, 0x0a,
0x30, 0x30, 0x32, 0x5f, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x05, 0x2a, 0x8e, 0x01, 0x0a, 0x0e, 0x0d, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x31, 0x5f, 0x31, 0x5f, 0x30, 0x10, 0x05,
0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0b, 0x2a, 0x65, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x76,
0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01,
0x50, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x42, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x31, 0x5f, 0x30,
0x12, 0x15, 0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x30, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x31, 0x5f,
0x5f, 0x54, 0x44, 0x4f, 0x41, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x30, 0x5f, 0x31, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x31,
0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x52, 0x53, 0x53, 0x49, 0x10, 0x04, 0x12, 0x15, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f,
0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x47, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x05, 0x2a, 0x8e, 0x01, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61,
0x4e, 0x53, 0x53, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e,
0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x46, 0x49, 0x10, 0x06, 0x2a, 0x2b, 0x0a, 0x0b, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x50, 0x53, 0x10, 0x01,
0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11,
0x4f, 0x55, 0x52, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x01, 0x12, 0x09, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x44, 0x4f,
0x0a, 0x05, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x02, 0x2a, 0x32, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x41, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c,
0x72, 0x69, 0x63, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x56, 0x45, 0x52, 0x5f, 0x52, 0x53, 0x53, 0x49, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x45,
0x45, 0x52, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x47, 0x4e, 0x53, 0x53, 0x10,
0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10, 0x02, 0x2a, 0x34, 0x0a, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x45, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45,
0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x5f, 0x57, 0x49, 0x46, 0x49, 0x10, 0x06, 0x2a, 0x2b, 0x0a, 0x0b, 0x41, 0x67, 0x67, 0x72,
0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x41, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x55, 0x52, 0x10,
0x53, 0x53, 0x5f, 0x42, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f,
0x43, 0x10, 0x02, 0x42, 0x69, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x4e, 0x54, 0x48, 0x10, 0x02, 0x2a, 0x32, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b,
0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x69, 0x6e, 0x64, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x10, 0x00,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x09,
0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10, 0x02, 0x2a, 0x34, 0x0a, 0x0b, 0x44, 0x65, 0x76,
0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53,
0x2f, 0x76, 0x34, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xaa, 0x02, 0x11, 0x43, 0x68, 0x69, 0x53, 0x5f, 0x41, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x42,
0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x43, 0x10, 0x02, 0x42,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x69, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b,
0x2e, 0x61, 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70,
0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x34, 0x2f,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xaa, 0x02, 0x11, 0x43, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74,
0x61, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (
@ -974,7 +1039,7 @@ func file_common_common_proto_rawDescGZIP() []byte {
} }
var file_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 9) var file_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
var file_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_common_common_proto_goTypes = []interface{}{ var file_common_common_proto_goTypes = []interface{}{
(Modulation)(0), // 0: common.Modulation (Modulation)(0), // 0: common.Modulation
(Region)(0), // 1: common.Region (Region)(0), // 1: common.Region
@ -989,18 +1054,20 @@ var file_common_common_proto_goTypes = []interface{}{
(*KeyEnvelope)(nil), // 10: common.KeyEnvelope (*KeyEnvelope)(nil), // 10: common.KeyEnvelope
(*Metric)(nil), // 11: common.Metric (*Metric)(nil), // 11: common.Metric
(*MetricDataset)(nil), // 12: common.MetricDataset (*MetricDataset)(nil), // 12: common.MetricDataset
(*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp (*JoinServerContext)(nil), // 13: common.JoinServerContext
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
} }
var file_common_common_proto_depIdxs = []int32{ var file_common_common_proto_depIdxs = []int32{
5, // 0: common.Location.source:type_name -> common.LocationSource 5, // 0: common.Location.source:type_name -> common.LocationSource
13, // 1: common.Metric.timestamps:type_name -> google.protobuf.Timestamp 14, // 1: common.Metric.timestamps:type_name -> google.protobuf.Timestamp
12, // 2: common.Metric.datasets:type_name -> common.MetricDataset 12, // 2: common.Metric.datasets:type_name -> common.MetricDataset
7, // 3: common.Metric.kind:type_name -> common.MetricKind 7, // 3: common.Metric.kind:type_name -> common.MetricKind
4, // [4:4] is the sub-list for method output_type 10, // 4: common.JoinServerContext.app_s_key:type_name -> common.KeyEnvelope
4, // [4:4] is the sub-list for method input_type 5, // [5:5] is the sub-list for method output_type
4, // [4:4] is the sub-list for extension type_name 5, // [5:5] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension extendee 5, // [5:5] is the sub-list for extension type_name
0, // [0:4] is the sub-list for field type_name 5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
} }
func init() { file_common_common_proto_init() } func init() { file_common_common_proto_init() }
@ -1057,6 +1124,18 @@ func file_common_common_proto_init() {
return nil return nil
} }
} }
file_common_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*JoinServerContext); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@ -1064,7 +1143,7 @@ func file_common_common_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_common_proto_rawDesc, RawDescriptor: file_common_common_proto_rawDesc,
NumEnums: 9, NumEnums: 9,
NumMessages: 4, NumMessages: 5,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -385,64 +385,6 @@ func (x *UplinkRelayRxInfo) GetWorChannel() uint32 {
return 0 return 0
} }
// Join-Server context.
type JoinServerContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Session-key ID.
SessionKeyId string `protobuf:"bytes,1,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"`
// AppSKey envelope.
AppSKey *common.KeyEnvelope `protobuf:"bytes,2,opt,name=app_s_key,json=appSKey,proto3" json:"app_s_key,omitempty"`
}
func (x *JoinServerContext) Reset() {
*x = JoinServerContext{}
if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *JoinServerContext) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*JoinServerContext) ProtoMessage() {}
func (x *JoinServerContext) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use JoinServerContext.ProtoReflect.Descriptor instead.
func (*JoinServerContext) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{2}
}
func (x *JoinServerContext) GetSessionKeyId() string {
if x != nil {
return x.SessionKeyId
}
return ""
}
func (x *JoinServerContext) GetAppSKey() *common.KeyEnvelope {
if x != nil {
return x.AppSKey
}
return nil
}
// UplinkEvent is the message sent when an uplink payload has been received. // UplinkEvent is the message sent when an uplink payload has been received.
type UplinkEvent struct { type UplinkEvent struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -482,13 +424,13 @@ type UplinkEvent struct {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext *JoinServerContext `protobuf:"bytes,15,opt,name=join_server_context,json=joinServerContext,proto3" json:"join_server_context,omitempty"` JoinServerContext *common.JoinServerContext `protobuf:"bytes,15,opt,name=join_server_context,json=joinServerContext,proto3" json:"join_server_context,omitempty"`
} }
func (x *UplinkEvent) Reset() { func (x *UplinkEvent) Reset() {
*x = UplinkEvent{} *x = UplinkEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[3] mi := &file_integration_integration_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -501,7 +443,7 @@ func (x *UplinkEvent) String() string {
func (*UplinkEvent) ProtoMessage() {} func (*UplinkEvent) ProtoMessage() {}
func (x *UplinkEvent) ProtoReflect() protoreflect.Message { func (x *UplinkEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[3] mi := &file_integration_integration_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -514,7 +456,7 @@ func (x *UplinkEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use UplinkEvent.ProtoReflect.Descriptor instead. // Deprecated: Use UplinkEvent.ProtoReflect.Descriptor instead.
func (*UplinkEvent) Descriptor() ([]byte, []int) { func (*UplinkEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{3} return file_integration_integration_proto_rawDescGZIP(), []int{2}
} }
func (x *UplinkEvent) GetDeduplicationId() string { func (x *UplinkEvent) GetDeduplicationId() string {
@ -615,7 +557,7 @@ func (x *UplinkEvent) GetRelayRxInfo() *UplinkRelayRxInfo {
return nil return nil
} }
func (x *UplinkEvent) GetJoinServerContext() *JoinServerContext { func (x *UplinkEvent) GetJoinServerContext() *common.JoinServerContext {
if x != nil { if x != nil {
return x.JoinServerContext return x.JoinServerContext
} }
@ -643,13 +585,13 @@ type JoinEvent struct {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext *JoinServerContext `protobuf:"bytes,6,opt,name=join_server_context,json=joinServerContext,proto3" json:"join_server_context,omitempty"` JoinServerContext *common.JoinServerContext `protobuf:"bytes,6,opt,name=join_server_context,json=joinServerContext,proto3" json:"join_server_context,omitempty"`
} }
func (x *JoinEvent) Reset() { func (x *JoinEvent) Reset() {
*x = JoinEvent{} *x = JoinEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[4] mi := &file_integration_integration_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -662,7 +604,7 @@ func (x *JoinEvent) String() string {
func (*JoinEvent) ProtoMessage() {} func (*JoinEvent) ProtoMessage() {}
func (x *JoinEvent) ProtoReflect() protoreflect.Message { func (x *JoinEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[4] mi := &file_integration_integration_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -675,7 +617,7 @@ func (x *JoinEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use JoinEvent.ProtoReflect.Descriptor instead. // Deprecated: Use JoinEvent.ProtoReflect.Descriptor instead.
func (*JoinEvent) Descriptor() ([]byte, []int) { func (*JoinEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{4} return file_integration_integration_proto_rawDescGZIP(), []int{3}
} }
func (x *JoinEvent) GetDeduplicationId() string { func (x *JoinEvent) GetDeduplicationId() string {
@ -713,7 +655,7 @@ func (x *JoinEvent) GetRelayRxInfo() *UplinkRelayRxInfo {
return nil return nil
} }
func (x *JoinEvent) GetJoinServerContext() *JoinServerContext { func (x *JoinEvent) GetJoinServerContext() *common.JoinServerContext {
if x != nil { if x != nil {
return x.JoinServerContext return x.JoinServerContext
} }
@ -744,7 +686,7 @@ type AckEvent struct {
func (x *AckEvent) Reset() { func (x *AckEvent) Reset() {
*x = AckEvent{} *x = AckEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[5] mi := &file_integration_integration_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -757,7 +699,7 @@ func (x *AckEvent) String() string {
func (*AckEvent) ProtoMessage() {} func (*AckEvent) ProtoMessage() {}
func (x *AckEvent) ProtoReflect() protoreflect.Message { func (x *AckEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[5] mi := &file_integration_integration_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -770,7 +712,7 @@ func (x *AckEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use AckEvent.ProtoReflect.Descriptor instead. // Deprecated: Use AckEvent.ProtoReflect.Descriptor instead.
func (*AckEvent) Descriptor() ([]byte, []int) { func (*AckEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{5} return file_integration_integration_proto_rawDescGZIP(), []int{4}
} }
func (x *AckEvent) GetDeduplicationId() string { func (x *AckEvent) GetDeduplicationId() string {
@ -842,7 +784,7 @@ type TxAckEvent struct {
func (x *TxAckEvent) Reset() { func (x *TxAckEvent) Reset() {
*x = TxAckEvent{} *x = TxAckEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[6] mi := &file_integration_integration_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -855,7 +797,7 @@ func (x *TxAckEvent) String() string {
func (*TxAckEvent) ProtoMessage() {} func (*TxAckEvent) ProtoMessage() {}
func (x *TxAckEvent) ProtoReflect() protoreflect.Message { func (x *TxAckEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[6] mi := &file_integration_integration_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -868,7 +810,7 @@ func (x *TxAckEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use TxAckEvent.ProtoReflect.Descriptor instead. // Deprecated: Use TxAckEvent.ProtoReflect.Descriptor instead.
func (*TxAckEvent) Descriptor() ([]byte, []int) { func (*TxAckEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{6} return file_integration_integration_proto_rawDescGZIP(), []int{5}
} }
func (x *TxAckEvent) GetDownlinkId() uint32 { func (x *TxAckEvent) GetDownlinkId() uint32 {
@ -943,7 +885,7 @@ type LogEvent struct {
func (x *LogEvent) Reset() { func (x *LogEvent) Reset() {
*x = LogEvent{} *x = LogEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[7] mi := &file_integration_integration_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -956,7 +898,7 @@ func (x *LogEvent) String() string {
func (*LogEvent) ProtoMessage() {} func (*LogEvent) ProtoMessage() {}
func (x *LogEvent) ProtoReflect() protoreflect.Message { func (x *LogEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[7] mi := &file_integration_integration_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -969,7 +911,7 @@ func (x *LogEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use LogEvent.ProtoReflect.Descriptor instead. // Deprecated: Use LogEvent.ProtoReflect.Descriptor instead.
func (*LogEvent) Descriptor() ([]byte, []int) { func (*LogEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{7} return file_integration_integration_proto_rawDescGZIP(), []int{6}
} }
func (x *LogEvent) GetTime() *timestamppb.Timestamp { func (x *LogEvent) GetTime() *timestamppb.Timestamp {
@ -1041,7 +983,7 @@ type StatusEvent struct {
func (x *StatusEvent) Reset() { func (x *StatusEvent) Reset() {
*x = StatusEvent{} *x = StatusEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[8] mi := &file_integration_integration_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1054,7 +996,7 @@ func (x *StatusEvent) String() string {
func (*StatusEvent) ProtoMessage() {} func (*StatusEvent) ProtoMessage() {}
func (x *StatusEvent) ProtoReflect() protoreflect.Message { func (x *StatusEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[8] mi := &file_integration_integration_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1067,7 +1009,7 @@ func (x *StatusEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use StatusEvent.ProtoReflect.Descriptor instead. // Deprecated: Use StatusEvent.ProtoReflect.Descriptor instead.
func (*StatusEvent) Descriptor() ([]byte, []int) { func (*StatusEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{8} return file_integration_integration_proto_rawDescGZIP(), []int{7}
} }
func (x *StatusEvent) GetDeduplicationId() string { func (x *StatusEvent) GetDeduplicationId() string {
@ -1138,7 +1080,7 @@ type LocationEvent struct {
func (x *LocationEvent) Reset() { func (x *LocationEvent) Reset() {
*x = LocationEvent{} *x = LocationEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[9] mi := &file_integration_integration_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1151,7 +1093,7 @@ func (x *LocationEvent) String() string {
func (*LocationEvent) ProtoMessage() {} func (*LocationEvent) ProtoMessage() {}
func (x *LocationEvent) ProtoReflect() protoreflect.Message { func (x *LocationEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[9] mi := &file_integration_integration_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1164,7 +1106,7 @@ func (x *LocationEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use LocationEvent.ProtoReflect.Descriptor instead. // Deprecated: Use LocationEvent.ProtoReflect.Descriptor instead.
func (*LocationEvent) Descriptor() ([]byte, []int) { func (*LocationEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{9} return file_integration_integration_proto_rawDescGZIP(), []int{8}
} }
func (x *LocationEvent) GetDeduplicationId() string { func (x *LocationEvent) GetDeduplicationId() string {
@ -1220,7 +1162,7 @@ type IntegrationEvent struct {
func (x *IntegrationEvent) Reset() { func (x *IntegrationEvent) Reset() {
*x = IntegrationEvent{} *x = IntegrationEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[10] mi := &file_integration_integration_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1233,7 +1175,7 @@ func (x *IntegrationEvent) String() string {
func (*IntegrationEvent) ProtoMessage() {} func (*IntegrationEvent) ProtoMessage() {}
func (x *IntegrationEvent) ProtoReflect() protoreflect.Message { func (x *IntegrationEvent) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[10] mi := &file_integration_integration_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1246,7 +1188,7 @@ func (x *IntegrationEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use IntegrationEvent.ProtoReflect.Descriptor instead. // Deprecated: Use IntegrationEvent.ProtoReflect.Descriptor instead.
func (*IntegrationEvent) Descriptor() ([]byte, []int) { func (*IntegrationEvent) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{10} return file_integration_integration_proto_rawDescGZIP(), []int{9}
} }
func (x *IntegrationEvent) GetDeduplicationId() string { func (x *IntegrationEvent) GetDeduplicationId() string {
@ -1318,7 +1260,7 @@ type DownlinkCommand struct {
func (x *DownlinkCommand) Reset() { func (x *DownlinkCommand) Reset() {
*x = DownlinkCommand{} *x = DownlinkCommand{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_integration_integration_proto_msgTypes[11] mi := &file_integration_integration_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1331,7 +1273,7 @@ func (x *DownlinkCommand) String() string {
func (*DownlinkCommand) ProtoMessage() {} func (*DownlinkCommand) ProtoMessage() {}
func (x *DownlinkCommand) ProtoReflect() protoreflect.Message { func (x *DownlinkCommand) ProtoReflect() protoreflect.Message {
mi := &file_integration_integration_proto_msgTypes[11] mi := &file_integration_integration_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1344,7 +1286,7 @@ func (x *DownlinkCommand) ProtoReflect() protoreflect.Message {
// Deprecated: Use DownlinkCommand.ProtoReflect.Descriptor instead. // Deprecated: Use DownlinkCommand.ProtoReflect.Descriptor instead.
func (*DownlinkCommand) Descriptor() ([]byte, []int) { func (*DownlinkCommand) Descriptor() ([]byte, []int) {
return file_integration_integration_proto_rawDescGZIP(), []int{11} return file_integration_integration_proto_rawDescGZIP(), []int{10}
} }
func (x *DownlinkCommand) GetId() string { func (x *DownlinkCommand) GetId() string {
@ -1441,221 +1383,214 @@ var file_integration_integration_proto_rawDesc = []byte{
0x01, 0x28, 0x05, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x73, 0x73, 0x69, 0x01, 0x28, 0x05, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x73, 0x73, 0x69,
0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x72, 0x73, 0x73, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x72, 0x73, 0x73, 0x69, 0x12, 0x1f, 0x0a, 0x0b,
0x77, 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x77, 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x6a, 0x0a, 0x0d, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0xd3, 0x04,
0x11, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x0a, 0x0b, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a,
0x78, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69,
0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x52, 0x07, 0x61, 0x70, 0x70, 0x53, 0x4b, 0x65, 0x79, 0x22, 0xd8, 0x04, 0x0a, 0x0b, 0x55, 0x70, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69,
0x6c, 0x69, 0x6e, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69,
0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e,
0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x10, 0x0a,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x03, 0x61, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x64, 0x72, 0x12,
0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x0e, 0x0a, 0x02, 0x64, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x64, 0x72, 0x12,
0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x43, 0x6e, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x08,
0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x64, 0x72, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x64, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a,
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x64, 0x72, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x5f, 0x63, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x12, 0x15, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x29,
0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x0a, 0x07, 0x72, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x72, 0x6d, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x10, 0x2e, 0x67, 0x77, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x78, 0x49, 0x6e, 0x66,
0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x6f, 0x52, 0x06, 0x72, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x29, 0x0a, 0x07, 0x74, 0x78, 0x5f,
0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x77, 0x2e,
0x65, 0x63, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x78,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x78,
0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x29, 0x0a, 0x07, 0x72, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e,
0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x77, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b,
0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x72, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x6c,
0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x29, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x61, 0x79, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x49, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x77, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18,
0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4a,
0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x52, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74,
0x65, 0x78, 0x74, 0x22, 0xca, 0x02, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64,
0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04,
0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64,
0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64,
0x72, 0x12, 0x42, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x78, 0x5f, 0x69, 0x6e,
0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x6c,
0x61, 0x79, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x52,
0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x49, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4a, 0x6f, 0x69, 0x6e,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x11, 0x6a,
0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x22, 0x85, 0x02, 0x0a, 0x08, 0x41, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a,
0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x71, 0x75, 0x65, 0x75, 0x65,
0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77,
0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x61, 0x63,
0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f,
0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08,
0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x22, 0xa5, 0x02, 0x0a, 0x0a, 0x54, 0x78, 0x41,
0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c,
0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x6f,
0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x71, 0x75, 0x65, 0x75, 0x65,
0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f,
0x64, 0x6f, 0x77, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e, 0x74,
0x44, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f,
0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
0x79, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x77, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
0x6e, 0x6b, 0x54, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x6e, 0x6b, 0x54, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x78, 0x49, 0x6e, 0x66, 0x6f,
0x12, 0x42, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x22, 0xe7, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a,
0x6f, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x6c, 0x61,
0x79, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x78,
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4e, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
0x74, 0x52, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x74, 0x65, 0x78, 0x74, 0x22, 0xcf, 0x02, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65,
0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a,
0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a,
0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61,
0x64, 0x72, 0x12, 0x42, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x78, 0x5f, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c,
0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x6c, 0x61, 0x79, 0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x20,
0x52, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4e, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20,
0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x3c, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28,
0x6e, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x65, 0x78, 0x74, 0x52, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x85, 0x02, 0x0a, 0x08, 0x41, 0x63, 0x6b, 0x45, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x3a,
0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcf, 0x02, 0x0a, 0x0b, 0x53,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01,
0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20,
0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x75, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x0b, 0x71, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74,
0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49,
0x28, 0x08, 0x52, 0x0c, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x64, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x22, 0xa5, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72,
0x02, 0x0a, 0x0a, 0x54, 0x78, 0x41, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x28, 0x0d, 0x52, 0x0a, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x64, 0x12, 0x2e, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x19, 0x62,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x75, 0x6e, 0x61,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x55, 0x6e, 0x61, 0x76,
0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x65,
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x72, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0c,
0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xd2, 0x01, 0x0a,
0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x75, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29,
0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x0b, 0x71, 0x75, 0x65, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c,
0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d,
0x52, 0x08, 0x66, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x61, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76,
0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x77, 0x2e, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76,
0x74, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xe7, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49,
0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c,
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x6e, 0x22, 0xa2, 0x02, 0x0a, 0x10, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x0a, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d,
0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61,
0x63, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x29, 0x0a, 0x10, 0x69,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f,
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e,
0x74, 0x65, 0x78, 0x74, 0x1a, 0x3a, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xb4, 0x01, 0x0a, 0x0f, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
0x22, 0xcf, 0x02, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65,
0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76,
0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x45, 0x75, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64,
0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x0d, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x06,
0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67,
0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2a, 0x2c, 0x0a,
0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46,
0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x4f, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x78, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x2a, 0xea, 0x01, 0x0a, 0x07,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
0x65, 0x12, 0x3a, 0x0a, 0x19, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x49, 0x4e, 0x4b,
0x65, 0x6c, 0x5f, 0x75, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x07, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x10, 0x01, 0x12,
0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x4c, 0x65, 0x76, 0x10, 0x0a, 0x0c, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x43, 0x10,
0x65, 0x6c, 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x43, 0x4f,
0x0d, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x44, 0x45, 0x43, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x54, 0x41, 0x41, 0x10, 0x04, 0x12,
0x20, 0x01, 0x28, 0x02, 0x52, 0x0c, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x4c, 0x65, 0x76, 0x16, 0x0a, 0x12, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x46, 0x5f, 0x43, 0x4e, 0x54, 0x5f,
0x65, 0x6c, 0x22, 0xd2, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x50, 0x4c, 0x49, 0x4e,
0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x4b, 0x5f, 0x4d, 0x49, 0x43, 0x10, 0x06, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x4c, 0x49, 0x4e,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x4b, 0x5f, 0x46, 0x5f, 0x43, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x4d,
0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x07, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x4f, 0x57, 0x4e,
0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x08, 0x12, 0x18,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x0a, 0x14, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4e, 0x45, 0x57, 0x5f, 0x45, 0x4e, 0x44, 0x5f,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x5f, 0x43, 0x4e,
0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x54, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x42, 0x81, 0x01, 0x0a, 0x1d, 0x69, 0x6f, 0x2e,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x69,
0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x10, 0x49, 0x6e, 0x74, 0x65,
0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x72, 0x6f, 0x63, 0x61,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x61, 0x72, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa2, 0x02, 0x0a, 0x10, 0x49, 0x6e, 0x74, 0x65, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x34, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6f, 0x6e, 0xaa, 0x02, 0x16, 0x43, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b,
0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66,
0x6f, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x74,
0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,
0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xb4, 0x01, 0x0a,
0x0f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72,
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
0x74, 0x61, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x2a, 0x2c, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12,
0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52,
0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
0x02, 0x2a, 0xea, 0x01, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a,
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x4f,
0x57, 0x4e, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x53,
0x49, 0x5a, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f,
0x43, 0x4f, 0x44, 0x45, 0x43, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x4f, 0x57, 0x4e, 0x4c,
0x49, 0x4e, 0x4b, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x43, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4f,
0x54, 0x41, 0x41, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f,
0x46, 0x5f, 0x43, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x05, 0x12, 0x0e, 0x0a,
0x0a, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4d, 0x49, 0x43, 0x10, 0x06, 0x12, 0x1f, 0x0a,
0x1b, 0x55, 0x50, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x46, 0x5f, 0x43, 0x4e, 0x54, 0x5f, 0x52, 0x45,
0x54, 0x52, 0x41, 0x4e, 0x53, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x07, 0x12, 0x14,
0x0a, 0x10, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x57,
0x41, 0x59, 0x10, 0x08, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4e, 0x45,
0x57, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x10, 0x09, 0x12, 0x0e,
0x0a, 0x0a, 0x46, 0x5f, 0x43, 0x4e, 0x54, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x42, 0x81,
0x01, 0x0a, 0x1d, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x42, 0x10, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x62, 0x72, 0x6f, 0x63, 0x61, 0x61, 0x72, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74,
0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x34, 0x2f, 0x69, 0x6e,
0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xaa, 0x02, 0x16, 0x43, 0x68, 0x69, 0x72,
0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -1671,72 +1606,70 @@ func file_integration_integration_proto_rawDescGZIP() []byte {
} }
var file_integration_integration_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_integration_integration_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_integration_integration_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_integration_integration_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_integration_integration_proto_goTypes = []interface{}{ var file_integration_integration_proto_goTypes = []interface{}{
(LogLevel)(0), // 0: integration.LogLevel (LogLevel)(0), // 0: integration.LogLevel
(LogCode)(0), // 1: integration.LogCode (LogCode)(0), // 1: integration.LogCode
(*DeviceInfo)(nil), // 2: integration.DeviceInfo (*DeviceInfo)(nil), // 2: integration.DeviceInfo
(*UplinkRelayRxInfo)(nil), // 3: integration.UplinkRelayRxInfo (*UplinkRelayRxInfo)(nil), // 3: integration.UplinkRelayRxInfo
(*JoinServerContext)(nil), // 4: integration.JoinServerContext (*UplinkEvent)(nil), // 4: integration.UplinkEvent
(*UplinkEvent)(nil), // 5: integration.UplinkEvent (*JoinEvent)(nil), // 5: integration.JoinEvent
(*JoinEvent)(nil), // 6: integration.JoinEvent (*AckEvent)(nil), // 6: integration.AckEvent
(*AckEvent)(nil), // 7: integration.AckEvent (*TxAckEvent)(nil), // 7: integration.TxAckEvent
(*TxAckEvent)(nil), // 8: integration.TxAckEvent (*LogEvent)(nil), // 8: integration.LogEvent
(*LogEvent)(nil), // 9: integration.LogEvent (*StatusEvent)(nil), // 9: integration.StatusEvent
(*StatusEvent)(nil), // 10: integration.StatusEvent (*LocationEvent)(nil), // 10: integration.LocationEvent
(*LocationEvent)(nil), // 11: integration.LocationEvent (*IntegrationEvent)(nil), // 11: integration.IntegrationEvent
(*IntegrationEvent)(nil), // 12: integration.IntegrationEvent (*DownlinkCommand)(nil), // 12: integration.DownlinkCommand
(*DownlinkCommand)(nil), // 13: integration.DownlinkCommand nil, // 13: integration.DeviceInfo.TagsEntry
nil, // 14: integration.DeviceInfo.TagsEntry nil, // 14: integration.LogEvent.ContextEntry
nil, // 15: integration.LogEvent.ContextEntry (common.DeviceClass)(0), // 15: common.DeviceClass
(common.DeviceClass)(0), // 16: common.DeviceClass (*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp
(*common.KeyEnvelope)(nil), // 17: common.KeyEnvelope (*structpb.Struct)(nil), // 17: google.protobuf.Struct
(*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp (*gw.UplinkRxInfo)(nil), // 18: gw.UplinkRxInfo
(*structpb.Struct)(nil), // 19: google.protobuf.Struct (*gw.UplinkTxInfo)(nil), // 19: gw.UplinkTxInfo
(*gw.UplinkRxInfo)(nil), // 20: gw.UplinkRxInfo (*common.JoinServerContext)(nil), // 20: common.JoinServerContext
(*gw.UplinkTxInfo)(nil), // 21: gw.UplinkTxInfo (*gw.DownlinkTxInfo)(nil), // 21: gw.DownlinkTxInfo
(*gw.DownlinkTxInfo)(nil), // 22: gw.DownlinkTxInfo (*common.Location)(nil), // 22: common.Location
(*common.Location)(nil), // 23: common.Location
} }
var file_integration_integration_proto_depIdxs = []int32{ var file_integration_integration_proto_depIdxs = []int32{
16, // 0: integration.DeviceInfo.device_class_enabled:type_name -> common.DeviceClass 15, // 0: integration.DeviceInfo.device_class_enabled:type_name -> common.DeviceClass
14, // 1: integration.DeviceInfo.tags:type_name -> integration.DeviceInfo.TagsEntry 13, // 1: integration.DeviceInfo.tags:type_name -> integration.DeviceInfo.TagsEntry
17, // 2: integration.JoinServerContext.app_s_key:type_name -> common.KeyEnvelope 16, // 2: integration.UplinkEvent.time:type_name -> google.protobuf.Timestamp
18, // 3: integration.UplinkEvent.time:type_name -> google.protobuf.Timestamp 2, // 3: integration.UplinkEvent.device_info:type_name -> integration.DeviceInfo
2, // 4: integration.UplinkEvent.device_info:type_name -> integration.DeviceInfo 17, // 4: integration.UplinkEvent.object:type_name -> google.protobuf.Struct
19, // 5: integration.UplinkEvent.object:type_name -> google.protobuf.Struct 18, // 5: integration.UplinkEvent.rx_info:type_name -> gw.UplinkRxInfo
20, // 6: integration.UplinkEvent.rx_info:type_name -> gw.UplinkRxInfo 19, // 6: integration.UplinkEvent.tx_info:type_name -> gw.UplinkTxInfo
21, // 7: integration.UplinkEvent.tx_info:type_name -> gw.UplinkTxInfo 3, // 7: integration.UplinkEvent.relay_rx_info:type_name -> integration.UplinkRelayRxInfo
3, // 8: integration.UplinkEvent.relay_rx_info:type_name -> integration.UplinkRelayRxInfo 20, // 8: integration.UplinkEvent.join_server_context:type_name -> common.JoinServerContext
4, // 9: integration.UplinkEvent.join_server_context:type_name -> integration.JoinServerContext 16, // 9: integration.JoinEvent.time:type_name -> google.protobuf.Timestamp
18, // 10: integration.JoinEvent.time:type_name -> google.protobuf.Timestamp 2, // 10: integration.JoinEvent.device_info:type_name -> integration.DeviceInfo
2, // 11: integration.JoinEvent.device_info:type_name -> integration.DeviceInfo 3, // 11: integration.JoinEvent.relay_rx_info:type_name -> integration.UplinkRelayRxInfo
3, // 12: integration.JoinEvent.relay_rx_info:type_name -> integration.UplinkRelayRxInfo 20, // 12: integration.JoinEvent.join_server_context:type_name -> common.JoinServerContext
4, // 13: integration.JoinEvent.join_server_context:type_name -> integration.JoinServerContext 16, // 13: integration.AckEvent.time:type_name -> google.protobuf.Timestamp
18, // 14: integration.AckEvent.time:type_name -> google.protobuf.Timestamp 2, // 14: integration.AckEvent.device_info:type_name -> integration.DeviceInfo
2, // 15: integration.AckEvent.device_info:type_name -> integration.DeviceInfo 16, // 15: integration.TxAckEvent.time:type_name -> google.protobuf.Timestamp
18, // 16: integration.TxAckEvent.time:type_name -> google.protobuf.Timestamp 2, // 16: integration.TxAckEvent.device_info:type_name -> integration.DeviceInfo
2, // 17: integration.TxAckEvent.device_info:type_name -> integration.DeviceInfo 21, // 17: integration.TxAckEvent.tx_info:type_name -> gw.DownlinkTxInfo
22, // 18: integration.TxAckEvent.tx_info:type_name -> gw.DownlinkTxInfo 16, // 18: integration.LogEvent.time:type_name -> google.protobuf.Timestamp
18, // 19: integration.LogEvent.time:type_name -> google.protobuf.Timestamp 2, // 19: integration.LogEvent.device_info:type_name -> integration.DeviceInfo
2, // 20: integration.LogEvent.device_info:type_name -> integration.DeviceInfo 0, // 20: integration.LogEvent.level:type_name -> integration.LogLevel
0, // 21: integration.LogEvent.level:type_name -> integration.LogLevel 1, // 21: integration.LogEvent.code:type_name -> integration.LogCode
1, // 22: integration.LogEvent.code:type_name -> integration.LogCode 14, // 22: integration.LogEvent.context:type_name -> integration.LogEvent.ContextEntry
15, // 23: integration.LogEvent.context:type_name -> integration.LogEvent.ContextEntry 16, // 23: integration.StatusEvent.time:type_name -> google.protobuf.Timestamp
18, // 24: integration.StatusEvent.time:type_name -> google.protobuf.Timestamp 2, // 24: integration.StatusEvent.device_info:type_name -> integration.DeviceInfo
2, // 25: integration.StatusEvent.device_info:type_name -> integration.DeviceInfo 16, // 25: integration.LocationEvent.time:type_name -> google.protobuf.Timestamp
18, // 26: integration.LocationEvent.time:type_name -> google.protobuf.Timestamp 2, // 26: integration.LocationEvent.device_info:type_name -> integration.DeviceInfo
2, // 27: integration.LocationEvent.device_info:type_name -> integration.DeviceInfo 22, // 27: integration.LocationEvent.location:type_name -> common.Location
23, // 28: integration.LocationEvent.location:type_name -> common.Location 16, // 28: integration.IntegrationEvent.time:type_name -> google.protobuf.Timestamp
18, // 29: integration.IntegrationEvent.time:type_name -> google.protobuf.Timestamp 2, // 29: integration.IntegrationEvent.device_info:type_name -> integration.DeviceInfo
2, // 30: integration.IntegrationEvent.device_info:type_name -> integration.DeviceInfo 17, // 30: integration.IntegrationEvent.object:type_name -> google.protobuf.Struct
19, // 31: integration.IntegrationEvent.object:type_name -> google.protobuf.Struct 17, // 31: integration.DownlinkCommand.object:type_name -> google.protobuf.Struct
19, // 32: integration.DownlinkCommand.object:type_name -> google.protobuf.Struct 32, // [32:32] is the sub-list for method output_type
33, // [33:33] is the sub-list for method output_type 32, // [32:32] is the sub-list for method input_type
33, // [33:33] is the sub-list for method input_type 32, // [32:32] is the sub-list for extension type_name
33, // [33:33] is the sub-list for extension type_name 32, // [32:32] is the sub-list for extension extendee
33, // [33:33] is the sub-list for extension extendee 0, // [0:32] is the sub-list for field type_name
0, // [0:33] is the sub-list for field type_name
} }
func init() { file_integration_integration_proto_init() } func init() { file_integration_integration_proto_init() }
@ -1770,18 +1703,6 @@ func file_integration_integration_proto_init() {
} }
} }
file_integration_integration_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*JoinServerContext); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integration_integration_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UplinkEvent); i { switch v := v.(*UplinkEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1793,7 +1714,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*JoinEvent); i { switch v := v.(*JoinEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1805,7 +1726,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AckEvent); i { switch v := v.(*AckEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1817,7 +1738,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TxAckEvent); i { switch v := v.(*TxAckEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1829,7 +1750,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LogEvent); i { switch v := v.(*LogEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1841,7 +1762,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StatusEvent); i { switch v := v.(*StatusEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1853,7 +1774,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LocationEvent); i { switch v := v.(*LocationEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1865,7 +1786,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IntegrationEvent); i { switch v := v.(*IntegrationEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1877,7 +1798,7 @@ func file_integration_integration_proto_init() {
return nil return nil
} }
} }
file_integration_integration_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { file_integration_integration_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DownlinkCommand); i { switch v := v.(*DownlinkCommand); i {
case 0: case 0:
return &v.state return &v.state
@ -1896,7 +1817,7 @@ func file_integration_integration_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_integration_integration_proto_rawDesc, RawDescriptor: file_integration_integration_proto_rawDesc,
NumEnums: 2, NumEnums: 2,
NumMessages: 14, NumMessages: 13,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -573,6 +573,11 @@ export class GetDeviceActivationResponse extends jspb.Message {
hasDeviceActivation(): boolean; hasDeviceActivation(): boolean;
clearDeviceActivation(): GetDeviceActivationResponse; clearDeviceActivation(): GetDeviceActivationResponse;
getJoinServerContext(): common_common_pb.JoinServerContext | undefined;
setJoinServerContext(value?: common_common_pb.JoinServerContext): GetDeviceActivationResponse;
hasJoinServerContext(): boolean;
clearJoinServerContext(): GetDeviceActivationResponse;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceActivationResponse.AsObject; toObject(includeInstance?: boolean): GetDeviceActivationResponse.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceActivationResponse): GetDeviceActivationResponse.AsObject; static toObject(includeInstance: boolean, msg: GetDeviceActivationResponse): GetDeviceActivationResponse.AsObject;
@ -584,6 +589,7 @@ export class GetDeviceActivationResponse extends jspb.Message {
export namespace GetDeviceActivationResponse { export namespace GetDeviceActivationResponse {
export type AsObject = { export type AsObject = {
deviceActivation?: DeviceActivation.AsObject, deviceActivation?: DeviceActivation.AsObject,
joinServerContext?: common_common_pb.JoinServerContext.AsObject,
} }
} }

View File

@ -5091,7 +5091,8 @@ proto.api.GetDeviceActivationResponse.prototype.toObject = function(opt_includeI
*/ */
proto.api.GetDeviceActivationResponse.toObject = function(includeInstance, msg) { proto.api.GetDeviceActivationResponse.toObject = function(includeInstance, msg) {
var f, obj = { var f, obj = {
deviceActivation: (f = msg.getDeviceActivation()) && proto.api.DeviceActivation.toObject(includeInstance, f) deviceActivation: (f = msg.getDeviceActivation()) && proto.api.DeviceActivation.toObject(includeInstance, f),
joinServerContext: (f = msg.getJoinServerContext()) && common_common_pb.JoinServerContext.toObject(includeInstance, f)
}; };
if (includeInstance) { if (includeInstance) {
@ -5133,6 +5134,11 @@ proto.api.GetDeviceActivationResponse.deserializeBinaryFromReader = function(msg
reader.readMessage(value,proto.api.DeviceActivation.deserializeBinaryFromReader); reader.readMessage(value,proto.api.DeviceActivation.deserializeBinaryFromReader);
msg.setDeviceActivation(value); msg.setDeviceActivation(value);
break; break;
case 2:
var value = new common_common_pb.JoinServerContext;
reader.readMessage(value,common_common_pb.JoinServerContext.deserializeBinaryFromReader);
msg.setJoinServerContext(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@ -5170,6 +5176,14 @@ proto.api.GetDeviceActivationResponse.serializeBinaryToWriter = function(message
proto.api.DeviceActivation.serializeBinaryToWriter proto.api.DeviceActivation.serializeBinaryToWriter
); );
} }
f = message.getJoinServerContext();
if (f != null) {
writer.writeMessage(
2,
f,
common_common_pb.JoinServerContext.serializeBinaryToWriter
);
}
}; };
@ -5210,6 +5224,43 @@ proto.api.GetDeviceActivationResponse.prototype.hasDeviceActivation = function()
}; };
/**
* optional common.JoinServerContext join_server_context = 2;
* @return {?proto.common.JoinServerContext}
*/
proto.api.GetDeviceActivationResponse.prototype.getJoinServerContext = function() {
return /** @type{?proto.common.JoinServerContext} */ (
jspb.Message.getWrapperField(this, common_common_pb.JoinServerContext, 2));
};
/**
* @param {?proto.common.JoinServerContext|undefined} value
* @return {!proto.api.GetDeviceActivationResponse} returns this
*/
proto.api.GetDeviceActivationResponse.prototype.setJoinServerContext = function(value) {
return jspb.Message.setWrapperField(this, 2, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.api.GetDeviceActivationResponse} returns this
*/
proto.api.GetDeviceActivationResponse.prototype.clearJoinServerContext = function() {
return this.setJoinServerContext(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.api.GetDeviceActivationResponse.prototype.hasJoinServerContext = function() {
return jspb.Message.getField(this, 2) != null;
};

View File

@ -119,6 +119,30 @@ export namespace MetricDataset {
} }
} }
export class JoinServerContext extends jspb.Message {
getSessionKeyId(): string;
setSessionKeyId(value: string): JoinServerContext;
getAppSKey(): KeyEnvelope | undefined;
setAppSKey(value?: KeyEnvelope): JoinServerContext;
hasAppSKey(): boolean;
clearAppSKey(): JoinServerContext;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): JoinServerContext.AsObject;
static toObject(includeInstance: boolean, msg: JoinServerContext): JoinServerContext.AsObject;
static serializeBinaryToWriter(message: JoinServerContext, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): JoinServerContext;
static deserializeBinaryFromReader(message: JoinServerContext, reader: jspb.BinaryReader): JoinServerContext;
}
export namespace JoinServerContext {
export type AsObject = {
sessionKeyId: string,
appSKey?: KeyEnvelope.AsObject,
}
}
export enum Modulation { export enum Modulation {
LORA = 0, LORA = 0,
FSK = 1, FSK = 1,

View File

@ -16,6 +16,7 @@ var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/time
goog.object.extend(proto, google_protobuf_timestamp_pb); goog.object.extend(proto, google_protobuf_timestamp_pb);
goog.exportSymbol('proto.common.Aggregation', null, global); goog.exportSymbol('proto.common.Aggregation', null, global);
goog.exportSymbol('proto.common.DeviceClass', null, global); goog.exportSymbol('proto.common.DeviceClass', null, global);
goog.exportSymbol('proto.common.JoinServerContext', null, global);
goog.exportSymbol('proto.common.KeyEnvelope', null, global); goog.exportSymbol('proto.common.KeyEnvelope', null, global);
goog.exportSymbol('proto.common.Location', null, global); goog.exportSymbol('proto.common.Location', null, global);
goog.exportSymbol('proto.common.LocationSource', null, global); goog.exportSymbol('proto.common.LocationSource', null, global);
@ -111,6 +112,27 @@ if (goog.DEBUG && !COMPILED) {
*/ */
proto.common.MetricDataset.displayName = 'proto.common.MetricDataset'; proto.common.MetricDataset.displayName = 'proto.common.MetricDataset';
} }
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.common.JoinServerContext = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.common.JoinServerContext, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.common.JoinServerContext.displayName = 'proto.common.JoinServerContext';
}
@ -1004,6 +1026,187 @@ proto.common.MetricDataset.prototype.clearDataList = function() {
}; };
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.common.JoinServerContext.prototype.toObject = function(opt_includeInstance) {
return proto.common.JoinServerContext.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.common.JoinServerContext} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.common.JoinServerContext.toObject = function(includeInstance, msg) {
var f, obj = {
sessionKeyId: jspb.Message.getFieldWithDefault(msg, 1, ""),
appSKey: (f = msg.getAppSKey()) && proto.common.KeyEnvelope.toObject(includeInstance, f)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.common.JoinServerContext}
*/
proto.common.JoinServerContext.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.common.JoinServerContext;
return proto.common.JoinServerContext.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.common.JoinServerContext} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.common.JoinServerContext}
*/
proto.common.JoinServerContext.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setSessionKeyId(value);
break;
case 2:
var value = new proto.common.KeyEnvelope;
reader.readMessage(value,proto.common.KeyEnvelope.deserializeBinaryFromReader);
msg.setAppSKey(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.common.JoinServerContext.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.common.JoinServerContext.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.common.JoinServerContext} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.common.JoinServerContext.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getSessionKeyId();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = message.getAppSKey();
if (f != null) {
writer.writeMessage(
2,
f,
proto.common.KeyEnvelope.serializeBinaryToWriter
);
}
};
/**
* optional string session_key_id = 1;
* @return {string}
*/
proto.common.JoinServerContext.prototype.getSessionKeyId = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.setSessionKeyId = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
/**
* optional KeyEnvelope app_s_key = 2;
* @return {?proto.common.KeyEnvelope}
*/
proto.common.JoinServerContext.prototype.getAppSKey = function() {
return /** @type{?proto.common.KeyEnvelope} */ (
jspb.Message.getWrapperField(this, proto.common.KeyEnvelope, 2));
};
/**
* @param {?proto.common.KeyEnvelope|undefined} value
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.setAppSKey = function(value) {
return jspb.Message.setWrapperField(this, 2, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.clearAppSKey = function() {
return this.setAppSKey(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.common.JoinServerContext.prototype.hasAppSKey = function() {
return jspb.Message.getField(this, 2) != null;
};
/** /**
* @enum {number} * @enum {number}
*/ */

View File

@ -612,6 +612,11 @@ export class GetDeviceActivationResponse extends jspb.Message {
getDeviceActivation(): DeviceActivation | undefined; getDeviceActivation(): DeviceActivation | undefined;
setDeviceActivation(value?: DeviceActivation): void; setDeviceActivation(value?: DeviceActivation): void;
hasJoinServerContext(): boolean;
clearJoinServerContext(): void;
getJoinServerContext(): common_common_pb.JoinServerContext | undefined;
setJoinServerContext(value?: common_common_pb.JoinServerContext): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceActivationResponse.AsObject; toObject(includeInstance?: boolean): GetDeviceActivationResponse.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceActivationResponse): GetDeviceActivationResponse.AsObject; static toObject(includeInstance: boolean, msg: GetDeviceActivationResponse): GetDeviceActivationResponse.AsObject;
@ -625,6 +630,7 @@ export class GetDeviceActivationResponse extends jspb.Message {
export namespace GetDeviceActivationResponse { export namespace GetDeviceActivationResponse {
export type AsObject = { export type AsObject = {
deviceActivation?: DeviceActivation.AsObject, deviceActivation?: DeviceActivation.AsObject,
joinServerContext?: common_common_pb.JoinServerContext.AsObject,
} }
} }

View File

@ -5091,7 +5091,8 @@ proto.api.GetDeviceActivationResponse.prototype.toObject = function(opt_includeI
*/ */
proto.api.GetDeviceActivationResponse.toObject = function(includeInstance, msg) { proto.api.GetDeviceActivationResponse.toObject = function(includeInstance, msg) {
var f, obj = { var f, obj = {
deviceActivation: (f = msg.getDeviceActivation()) && proto.api.DeviceActivation.toObject(includeInstance, f) deviceActivation: (f = msg.getDeviceActivation()) && proto.api.DeviceActivation.toObject(includeInstance, f),
joinServerContext: (f = msg.getJoinServerContext()) && common_common_pb.JoinServerContext.toObject(includeInstance, f)
}; };
if (includeInstance) { if (includeInstance) {
@ -5133,6 +5134,11 @@ proto.api.GetDeviceActivationResponse.deserializeBinaryFromReader = function(msg
reader.readMessage(value,proto.api.DeviceActivation.deserializeBinaryFromReader); reader.readMessage(value,proto.api.DeviceActivation.deserializeBinaryFromReader);
msg.setDeviceActivation(value); msg.setDeviceActivation(value);
break; break;
case 2:
var value = new common_common_pb.JoinServerContext;
reader.readMessage(value,common_common_pb.JoinServerContext.deserializeBinaryFromReader);
msg.setJoinServerContext(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@ -5170,6 +5176,14 @@ proto.api.GetDeviceActivationResponse.serializeBinaryToWriter = function(message
proto.api.DeviceActivation.serializeBinaryToWriter proto.api.DeviceActivation.serializeBinaryToWriter
); );
} }
f = message.getJoinServerContext();
if (f != null) {
writer.writeMessage(
2,
f,
common_common_pb.JoinServerContext.serializeBinaryToWriter
);
}
}; };
@ -5210,6 +5224,43 @@ proto.api.GetDeviceActivationResponse.prototype.hasDeviceActivation = function()
}; };
/**
* optional common.JoinServerContext join_server_context = 2;
* @return {?proto.common.JoinServerContext}
*/
proto.api.GetDeviceActivationResponse.prototype.getJoinServerContext = function() {
return /** @type{?proto.common.JoinServerContext} */ (
jspb.Message.getWrapperField(this, common_common_pb.JoinServerContext, 2));
};
/**
* @param {?proto.common.JoinServerContext|undefined} value
* @return {!proto.api.GetDeviceActivationResponse} returns this
*/
proto.api.GetDeviceActivationResponse.prototype.setJoinServerContext = function(value) {
return jspb.Message.setWrapperField(this, 2, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.api.GetDeviceActivationResponse} returns this
*/
proto.api.GetDeviceActivationResponse.prototype.clearJoinServerContext = function() {
return this.setJoinServerContext(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.api.GetDeviceActivationResponse.prototype.hasJoinServerContext = function() {
return jspb.Message.getField(this, 2) != null;
};

View File

@ -128,6 +128,32 @@ export namespace MetricDataset {
} }
} }
export class JoinServerContext extends jspb.Message {
getSessionKeyId(): string;
setSessionKeyId(value: string): void;
hasAppSKey(): boolean;
clearAppSKey(): void;
getAppSKey(): KeyEnvelope | undefined;
setAppSKey(value?: KeyEnvelope): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): JoinServerContext.AsObject;
static toObject(includeInstance: boolean, msg: JoinServerContext): JoinServerContext.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: JoinServerContext, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): JoinServerContext;
static deserializeBinaryFromReader(message: JoinServerContext, reader: jspb.BinaryReader): JoinServerContext;
}
export namespace JoinServerContext {
export type AsObject = {
sessionKeyId: string,
appSKey?: KeyEnvelope.AsObject,
}
}
export interface ModulationMap { export interface ModulationMap {
LORA: 0; LORA: 0;
FSK: 1; FSK: 1;

View File

@ -16,6 +16,7 @@ var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/time
goog.object.extend(proto, google_protobuf_timestamp_pb); goog.object.extend(proto, google_protobuf_timestamp_pb);
goog.exportSymbol('proto.common.Aggregation', null, global); goog.exportSymbol('proto.common.Aggregation', null, global);
goog.exportSymbol('proto.common.DeviceClass', null, global); goog.exportSymbol('proto.common.DeviceClass', null, global);
goog.exportSymbol('proto.common.JoinServerContext', null, global);
goog.exportSymbol('proto.common.KeyEnvelope', null, global); goog.exportSymbol('proto.common.KeyEnvelope', null, global);
goog.exportSymbol('proto.common.Location', null, global); goog.exportSymbol('proto.common.Location', null, global);
goog.exportSymbol('proto.common.LocationSource', null, global); goog.exportSymbol('proto.common.LocationSource', null, global);
@ -111,6 +112,27 @@ if (goog.DEBUG && !COMPILED) {
*/ */
proto.common.MetricDataset.displayName = 'proto.common.MetricDataset'; proto.common.MetricDataset.displayName = 'proto.common.MetricDataset';
} }
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.common.JoinServerContext = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.common.JoinServerContext, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.common.JoinServerContext.displayName = 'proto.common.JoinServerContext';
}
@ -1004,6 +1026,187 @@ proto.common.MetricDataset.prototype.clearDataList = function() {
}; };
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.common.JoinServerContext.prototype.toObject = function(opt_includeInstance) {
return proto.common.JoinServerContext.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.common.JoinServerContext} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.common.JoinServerContext.toObject = function(includeInstance, msg) {
var f, obj = {
sessionKeyId: jspb.Message.getFieldWithDefault(msg, 1, ""),
appSKey: (f = msg.getAppSKey()) && proto.common.KeyEnvelope.toObject(includeInstance, f)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.common.JoinServerContext}
*/
proto.common.JoinServerContext.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.common.JoinServerContext;
return proto.common.JoinServerContext.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.common.JoinServerContext} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.common.JoinServerContext}
*/
proto.common.JoinServerContext.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setSessionKeyId(value);
break;
case 2:
var value = new proto.common.KeyEnvelope;
reader.readMessage(value,proto.common.KeyEnvelope.deserializeBinaryFromReader);
msg.setAppSKey(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.common.JoinServerContext.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.common.JoinServerContext.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.common.JoinServerContext} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.common.JoinServerContext.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getSessionKeyId();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = message.getAppSKey();
if (f != null) {
writer.writeMessage(
2,
f,
proto.common.KeyEnvelope.serializeBinaryToWriter
);
}
};
/**
* optional string session_key_id = 1;
* @return {string}
*/
proto.common.JoinServerContext.prototype.getSessionKeyId = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.setSessionKeyId = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
/**
* optional KeyEnvelope app_s_key = 2;
* @return {?proto.common.KeyEnvelope}
*/
proto.common.JoinServerContext.prototype.getAppSKey = function() {
return /** @type{?proto.common.KeyEnvelope} */ (
jspb.Message.getWrapperField(this, proto.common.KeyEnvelope, 2));
};
/**
* @param {?proto.common.KeyEnvelope|undefined} value
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.setAppSKey = function(value) {
return jspb.Message.setWrapperField(this, 2, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.common.JoinServerContext} returns this
*/
proto.common.JoinServerContext.prototype.clearAppSKey = function() {
return this.setAppSKey(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.common.JoinServerContext.prototype.hasAppSKey = function() {
return jspb.Message.getField(this, 2) != null;
};
/** /**
* @enum {number} * @enum {number}
*/ */

View File

@ -102,32 +102,6 @@ export namespace UplinkRelayRxInfo {
} }
} }
export class JoinServerContext extends jspb.Message {
getSessionKeyId(): string;
setSessionKeyId(value: string): void;
hasAppSKey(): boolean;
clearAppSKey(): void;
getAppSKey(): common_common_pb.KeyEnvelope | undefined;
setAppSKey(value?: common_common_pb.KeyEnvelope): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): JoinServerContext.AsObject;
static toObject(includeInstance: boolean, msg: JoinServerContext): JoinServerContext.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: JoinServerContext, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): JoinServerContext;
static deserializeBinaryFromReader(message: JoinServerContext, reader: jspb.BinaryReader): JoinServerContext;
}
export namespace JoinServerContext {
export type AsObject = {
sessionKeyId: string,
appSKey?: common_common_pb.KeyEnvelope.AsObject,
}
}
export class UplinkEvent extends jspb.Message { export class UplinkEvent extends jspb.Message {
getDeduplicationId(): string; getDeduplicationId(): string;
setDeduplicationId(value: string): void; setDeduplicationId(value: string): void;
@ -187,8 +161,8 @@ export class UplinkEvent extends jspb.Message {
hasJoinServerContext(): boolean; hasJoinServerContext(): boolean;
clearJoinServerContext(): void; clearJoinServerContext(): void;
getJoinServerContext(): JoinServerContext | undefined; getJoinServerContext(): common_common_pb.JoinServerContext | undefined;
setJoinServerContext(value?: JoinServerContext): void; setJoinServerContext(value?: common_common_pb.JoinServerContext): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UplinkEvent.AsObject; toObject(includeInstance?: boolean): UplinkEvent.AsObject;
@ -216,7 +190,7 @@ export namespace UplinkEvent {
rxInfoList: Array<gw_gw_pb.UplinkRxInfo.AsObject>, rxInfoList: Array<gw_gw_pb.UplinkRxInfo.AsObject>,
txInfo?: gw_gw_pb.UplinkTxInfo.AsObject, txInfo?: gw_gw_pb.UplinkTxInfo.AsObject,
relayRxInfo?: UplinkRelayRxInfo.AsObject, relayRxInfo?: UplinkRelayRxInfo.AsObject,
joinServerContext?: JoinServerContext.AsObject, joinServerContext?: common_common_pb.JoinServerContext.AsObject,
} }
} }
@ -244,8 +218,8 @@ export class JoinEvent extends jspb.Message {
hasJoinServerContext(): boolean; hasJoinServerContext(): boolean;
clearJoinServerContext(): void; clearJoinServerContext(): void;
getJoinServerContext(): JoinServerContext | undefined; getJoinServerContext(): common_common_pb.JoinServerContext | undefined;
setJoinServerContext(value?: JoinServerContext): void; setJoinServerContext(value?: common_common_pb.JoinServerContext): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): JoinEvent.AsObject; toObject(includeInstance?: boolean): JoinEvent.AsObject;
@ -264,7 +238,7 @@ export namespace JoinEvent {
deviceInfo?: DeviceInfo.AsObject, deviceInfo?: DeviceInfo.AsObject,
devAddr: string, devAddr: string,
relayRxInfo?: UplinkRelayRxInfo.AsObject, relayRxInfo?: UplinkRelayRxInfo.AsObject,
joinServerContext?: JoinServerContext.AsObject, joinServerContext?: common_common_pb.JoinServerContext.AsObject,
} }
} }

View File

@ -25,7 +25,6 @@ goog.exportSymbol('proto.integration.DeviceInfo', null, global);
goog.exportSymbol('proto.integration.DownlinkCommand', null, global); goog.exportSymbol('proto.integration.DownlinkCommand', null, global);
goog.exportSymbol('proto.integration.IntegrationEvent', null, global); goog.exportSymbol('proto.integration.IntegrationEvent', null, global);
goog.exportSymbol('proto.integration.JoinEvent', null, global); goog.exportSymbol('proto.integration.JoinEvent', null, global);
goog.exportSymbol('proto.integration.JoinServerContext', null, global);
goog.exportSymbol('proto.integration.LocationEvent', null, global); goog.exportSymbol('proto.integration.LocationEvent', null, global);
goog.exportSymbol('proto.integration.LogCode', null, global); goog.exportSymbol('proto.integration.LogCode', null, global);
goog.exportSymbol('proto.integration.LogEvent', null, global); goog.exportSymbol('proto.integration.LogEvent', null, global);
@ -76,27 +75,6 @@ if (goog.DEBUG && !COMPILED) {
*/ */
proto.integration.UplinkRelayRxInfo.displayName = 'proto.integration.UplinkRelayRxInfo'; proto.integration.UplinkRelayRxInfo.displayName = 'proto.integration.UplinkRelayRxInfo';
} }
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.integration.JoinServerContext = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.integration.JoinServerContext, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.integration.JoinServerContext.displayName = 'proto.integration.JoinServerContext';
}
/** /**
* Generated by JsPbCodeGenerator. * Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a * @param {Array=} opt_data Optional initial data array, typically from a
@ -970,187 +948,6 @@ proto.integration.UplinkRelayRxInfo.prototype.setWorChannel = function(value) {
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.integration.JoinServerContext.prototype.toObject = function(opt_includeInstance) {
return proto.integration.JoinServerContext.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.integration.JoinServerContext} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.integration.JoinServerContext.toObject = function(includeInstance, msg) {
var f, obj = {
sessionKeyId: jspb.Message.getFieldWithDefault(msg, 1, ""),
appSKey: (f = msg.getAppSKey()) && common_common_pb.KeyEnvelope.toObject(includeInstance, f)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.integration.JoinServerContext}
*/
proto.integration.JoinServerContext.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.integration.JoinServerContext;
return proto.integration.JoinServerContext.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.integration.JoinServerContext} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.integration.JoinServerContext}
*/
proto.integration.JoinServerContext.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setSessionKeyId(value);
break;
case 2:
var value = new common_common_pb.KeyEnvelope;
reader.readMessage(value,common_common_pb.KeyEnvelope.deserializeBinaryFromReader);
msg.setAppSKey(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.integration.JoinServerContext.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.integration.JoinServerContext.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.integration.JoinServerContext} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.integration.JoinServerContext.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getSessionKeyId();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = message.getAppSKey();
if (f != null) {
writer.writeMessage(
2,
f,
common_common_pb.KeyEnvelope.serializeBinaryToWriter
);
}
};
/**
* optional string session_key_id = 1;
* @return {string}
*/
proto.integration.JoinServerContext.prototype.getSessionKeyId = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.integration.JoinServerContext} returns this
*/
proto.integration.JoinServerContext.prototype.setSessionKeyId = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
/**
* optional common.KeyEnvelope app_s_key = 2;
* @return {?proto.common.KeyEnvelope}
*/
proto.integration.JoinServerContext.prototype.getAppSKey = function() {
return /** @type{?proto.common.KeyEnvelope} */ (
jspb.Message.getWrapperField(this, common_common_pb.KeyEnvelope, 2));
};
/**
* @param {?proto.common.KeyEnvelope|undefined} value
* @return {!proto.integration.JoinServerContext} returns this
*/
proto.integration.JoinServerContext.prototype.setAppSKey = function(value) {
return jspb.Message.setWrapperField(this, 2, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.integration.JoinServerContext} returns this
*/
proto.integration.JoinServerContext.prototype.clearAppSKey = function() {
return this.setAppSKey(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.integration.JoinServerContext.prototype.hasAppSKey = function() {
return jspb.Message.getField(this, 2) != null;
};
/** /**
* List of repeated fields within this message type. * List of repeated fields within this message type.
* @private {!Array<number>} * @private {!Array<number>}
@ -1204,7 +1001,7 @@ proto.integration.UplinkEvent.toObject = function(includeInstance, msg) {
gw_gw_pb.UplinkRxInfo.toObject, includeInstance), gw_gw_pb.UplinkRxInfo.toObject, includeInstance),
txInfo: (f = msg.getTxInfo()) && gw_gw_pb.UplinkTxInfo.toObject(includeInstance, f), txInfo: (f = msg.getTxInfo()) && gw_gw_pb.UplinkTxInfo.toObject(includeInstance, f),
relayRxInfo: (f = msg.getRelayRxInfo()) && proto.integration.UplinkRelayRxInfo.toObject(includeInstance, f), relayRxInfo: (f = msg.getRelayRxInfo()) && proto.integration.UplinkRelayRxInfo.toObject(includeInstance, f),
joinServerContext: (f = msg.getJoinServerContext()) && proto.integration.JoinServerContext.toObject(includeInstance, f) joinServerContext: (f = msg.getJoinServerContext()) && common_common_pb.JoinServerContext.toObject(includeInstance, f)
}; };
if (includeInstance) { if (includeInstance) {
@ -1304,8 +1101,8 @@ proto.integration.UplinkEvent.deserializeBinaryFromReader = function(msg, reader
msg.setRelayRxInfo(value); msg.setRelayRxInfo(value);
break; break;
case 15: case 15:
var value = new proto.integration.JoinServerContext; var value = new common_common_pb.JoinServerContext;
reader.readMessage(value,proto.integration.JoinServerContext.deserializeBinaryFromReader); reader.readMessage(value,common_common_pb.JoinServerContext.deserializeBinaryFromReader);
msg.setJoinServerContext(value); msg.setJoinServerContext(value);
break; break;
default: default:
@ -1446,7 +1243,7 @@ proto.integration.UplinkEvent.serializeBinaryToWriter = function(message, writer
writer.writeMessage( writer.writeMessage(
15, 15,
f, f,
proto.integration.JoinServerContext.serializeBinaryToWriter common_common_pb.JoinServerContext.serializeBinaryToWriter
); );
} }
}; };
@ -1844,17 +1641,17 @@ proto.integration.UplinkEvent.prototype.hasRelayRxInfo = function() {
/** /**
* optional JoinServerContext join_server_context = 15; * optional common.JoinServerContext join_server_context = 15;
* @return {?proto.integration.JoinServerContext} * @return {?proto.common.JoinServerContext}
*/ */
proto.integration.UplinkEvent.prototype.getJoinServerContext = function() { proto.integration.UplinkEvent.prototype.getJoinServerContext = function() {
return /** @type{?proto.integration.JoinServerContext} */ ( return /** @type{?proto.common.JoinServerContext} */ (
jspb.Message.getWrapperField(this, proto.integration.JoinServerContext, 15)); jspb.Message.getWrapperField(this, common_common_pb.JoinServerContext, 15));
}; };
/** /**
* @param {?proto.integration.JoinServerContext|undefined} value * @param {?proto.common.JoinServerContext|undefined} value
* @return {!proto.integration.UplinkEvent} returns this * @return {!proto.integration.UplinkEvent} returns this
*/ */
proto.integration.UplinkEvent.prototype.setJoinServerContext = function(value) { proto.integration.UplinkEvent.prototype.setJoinServerContext = function(value) {
@ -1917,7 +1714,7 @@ proto.integration.JoinEvent.toObject = function(includeInstance, msg) {
deviceInfo: (f = msg.getDeviceInfo()) && proto.integration.DeviceInfo.toObject(includeInstance, f), deviceInfo: (f = msg.getDeviceInfo()) && proto.integration.DeviceInfo.toObject(includeInstance, f),
devAddr: jspb.Message.getFieldWithDefault(msg, 4, ""), devAddr: jspb.Message.getFieldWithDefault(msg, 4, ""),
relayRxInfo: (f = msg.getRelayRxInfo()) && proto.integration.UplinkRelayRxInfo.toObject(includeInstance, f), relayRxInfo: (f = msg.getRelayRxInfo()) && proto.integration.UplinkRelayRxInfo.toObject(includeInstance, f),
joinServerContext: (f = msg.getJoinServerContext()) && proto.integration.JoinServerContext.toObject(includeInstance, f) joinServerContext: (f = msg.getJoinServerContext()) && common_common_pb.JoinServerContext.toObject(includeInstance, f)
}; };
if (includeInstance) { if (includeInstance) {
@ -1978,8 +1775,8 @@ proto.integration.JoinEvent.deserializeBinaryFromReader = function(msg, reader)
msg.setRelayRxInfo(value); msg.setRelayRxInfo(value);
break; break;
case 6: case 6:
var value = new proto.integration.JoinServerContext; var value = new common_common_pb.JoinServerContext;
reader.readMessage(value,proto.integration.JoinServerContext.deserializeBinaryFromReader); reader.readMessage(value,common_common_pb.JoinServerContext.deserializeBinaryFromReader);
msg.setJoinServerContext(value); msg.setJoinServerContext(value);
break; break;
default: default:
@ -2054,7 +1851,7 @@ proto.integration.JoinEvent.serializeBinaryToWriter = function(message, writer)
writer.writeMessage( writer.writeMessage(
6, 6,
f, f,
proto.integration.JoinServerContext.serializeBinaryToWriter common_common_pb.JoinServerContext.serializeBinaryToWriter
); );
} }
}; };
@ -2208,17 +2005,17 @@ proto.integration.JoinEvent.prototype.hasRelayRxInfo = function() {
/** /**
* optional JoinServerContext join_server_context = 6; * optional common.JoinServerContext join_server_context = 6;
* @return {?proto.integration.JoinServerContext} * @return {?proto.common.JoinServerContext}
*/ */
proto.integration.JoinEvent.prototype.getJoinServerContext = function() { proto.integration.JoinEvent.prototype.getJoinServerContext = function() {
return /** @type{?proto.integration.JoinServerContext} */ ( return /** @type{?proto.common.JoinServerContext} */ (
jspb.Message.getWrapperField(this, proto.integration.JoinServerContext, 6)); jspb.Message.getWrapperField(this, common_common_pb.JoinServerContext, 6));
}; };
/** /**
* @param {?proto.integration.JoinServerContext|undefined} value * @param {?proto.common.JoinServerContext|undefined} value
* @return {!proto.integration.JoinEvent} returns this * @return {!proto.integration.JoinEvent} returns this
*/ */
proto.integration.JoinEvent.prototype.setJoinServerContext = function(value) { proto.integration.JoinEvent.prototype.setJoinServerContext = function(value) {

1
api/md/api/api.md vendored
View File

@ -2011,6 +2011,7 @@ applications.
| Field | Type | Label | Description | | Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- | | ----- | ---- | ----- | ----------- |
| device_activation | [DeviceActivation](#api-DeviceActivation) | | Device activation object. | | device_activation | [DeviceActivation](#api-DeviceActivation) | | Device activation object. |
| join_server_context | [common.JoinServerContext](#common-JoinServerContext) | | Join-Server context. A non-empty value indicatest that ChirpStack does not have access to the AppSKey and that the encryption / decryption of the payloads is the responsibility of the end-application. |

View File

@ -418,6 +418,12 @@ message GetDeviceActivationRequest {
message GetDeviceActivationResponse { message GetDeviceActivationResponse {
// Device activation object. // Device activation object.
DeviceActivation device_activation = 1; DeviceActivation device_activation = 1;
// Join-Server context.
// A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application.
common.JoinServerContext join_server_context = 2;
} }
message GetRandomDevAddrRequest { message GetRandomDevAddrRequest {

View File

@ -213,3 +213,12 @@ enum DeviceClass {
// Class-C. // Class-C.
CLASS_C = 2; CLASS_C = 2;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
KeyEnvelope app_s_key = 2;
}

View File

@ -114,15 +114,6 @@ message UplinkRelayRxInfo {
uint32 wor_channel = 6; uint32 wor_channel = 6;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
common.KeyEnvelope app_s_key = 2;
}
// UplinkEvent is the message sent when an uplink payload has been received. // UplinkEvent is the message sent when an uplink payload has been received.
message UplinkEvent { message UplinkEvent {
// Deduplication ID (UUID). // Deduplication ID (UUID).
@ -172,7 +163,7 @@ message UplinkEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 15; common.JoinServerContext join_server_context = 15;
} }
// JoinEvent is the message sent when a device joined the network. // JoinEvent is the message sent when a device joined the network.
@ -197,7 +188,7 @@ message JoinEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 6; common.JoinServerContext join_server_context = 6;
} }
// AckEvent is the message sent when a confirmation on a confirmed downlink // AckEvent is the message sent when a confirmation on a confirmed downlink

View File

@ -7,15 +7,9 @@ import "gw/gw.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
message DeviceSession { message DeviceSession {
// Device EUI.
bytes dev_eui = 1;
// Device address. // Device address.
bytes dev_addr = 2; bytes dev_addr = 2;
// Join EUI.
bytes join_eui = 3;
// LoRaWAN mac-version. // LoRaWAN mac-version.
common.MacVersion mac_version = 4; common.MacVersion mac_version = 4;

View File

@ -418,6 +418,12 @@ message GetDeviceActivationRequest {
message GetDeviceActivationResponse { message GetDeviceActivationResponse {
// Device activation object. // Device activation object.
DeviceActivation device_activation = 1; DeviceActivation device_activation = 1;
// Join-Server context.
// A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application.
common.JoinServerContext join_server_context = 2;
} }
message GetRandomDevAddrRequest { message GetRandomDevAddrRequest {

View File

@ -213,3 +213,12 @@ enum DeviceClass {
// Class-C. // Class-C.
CLASS_C = 2; CLASS_C = 2;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
KeyEnvelope app_s_key = 2;
}

View File

@ -114,15 +114,6 @@ message UplinkRelayRxInfo {
uint32 wor_channel = 6; uint32 wor_channel = 6;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
common.KeyEnvelope app_s_key = 2;
}
// UplinkEvent is the message sent when an uplink payload has been received. // UplinkEvent is the message sent when an uplink payload has been received.
message UplinkEvent { message UplinkEvent {
// Deduplication ID (UUID). // Deduplication ID (UUID).
@ -172,7 +163,7 @@ message UplinkEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 15; common.JoinServerContext join_server_context = 15;
} }
// JoinEvent is the message sent when a device joined the network. // JoinEvent is the message sent when a device joined the network.
@ -197,7 +188,7 @@ message JoinEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 6; common.JoinServerContext join_server_context = 6;
} }
// AckEvent is the message sent when a confirmation on a confirmed downlink // AckEvent is the message sent when a confirmation on a confirmed downlink

File diff suppressed because one or more lines are too long

View File

@ -227,10 +227,12 @@ class GetDeviceActivationRequest(_message.Message):
def __init__(self, dev_eui: _Optional[str] = ...) -> None: ... def __init__(self, dev_eui: _Optional[str] = ...) -> None: ...
class GetDeviceActivationResponse(_message.Message): class GetDeviceActivationResponse(_message.Message):
__slots__ = ("device_activation",) __slots__ = ("device_activation", "join_server_context")
DEVICE_ACTIVATION_FIELD_NUMBER: _ClassVar[int] DEVICE_ACTIVATION_FIELD_NUMBER: _ClassVar[int]
JOIN_SERVER_CONTEXT_FIELD_NUMBER: _ClassVar[int]
device_activation: DeviceActivation device_activation: DeviceActivation
def __init__(self, device_activation: _Optional[_Union[DeviceActivation, _Mapping]] = ...) -> None: ... join_server_context: _common_pb2.JoinServerContext
def __init__(self, device_activation: _Optional[_Union[DeviceActivation, _Mapping]] = ..., join_server_context: _Optional[_Union[_common_pb2.JoinServerContext, _Mapping]] = ...) -> None: ...
class GetRandomDevAddrRequest(_message.Message): class GetRandomDevAddrRequest(_message.Message):
__slots__ = ("dev_eui",) __slots__ = ("dev_eui",)

View File

@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"chirpstack-api/common/common.proto\x12\x06\x63ommon\x1a\x1fgoogle/protobuf/timestamp.proto\"{\n\x08Location\x12\x10\n\x08latitude\x18\x01 \x01(\x01\x12\x11\n\tlongitude\x18\x02 \x01(\x01\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x01\x12&\n\x06source\x18\x04 \x01(\x0e\x32\x16.common.LocationSource\x12\x10\n\x08\x61\x63\x63uracy\x18\x05 \x01(\x02\"1\n\x0bKeyEnvelope\x12\x11\n\tkek_label\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x65s_key\x18\x02 \x01(\x0c\"\x91\x01\n\x06Metric\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\ntimestamps\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x08\x64\x61tasets\x18\x03 \x03(\x0b\x32\x15.common.MetricDataset\x12 \n\x04kind\x18\x04 \x01(\x0e\x32\x12.common.MetricKind\",\n\rMetricDataset\x12\r\n\x05label\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02*,\n\nModulation\x12\x08\n\x04LORA\x10\x00\x12\x07\n\x03\x46SK\x10\x01\x12\x0b\n\x07LR_FHSS\x10\x02*\xaa\x01\n\x06Region\x12\t\n\x05\x45U868\x10\x00\x12\t\n\x05US915\x10\x02\x12\t\n\x05\x43N779\x10\x03\x12\t\n\x05\x45U433\x10\x04\x12\t\n\x05\x41U915\x10\x05\x12\t\n\x05\x43N470\x10\x06\x12\t\n\x05\x41S923\x10\x07\x12\x0b\n\x07\x41S923_2\x10\x0c\x12\x0b\n\x07\x41S923_3\x10\r\x12\x0b\n\x07\x41S923_4\x10\x0e\x12\t\n\x05KR920\x10\x08\x12\t\n\x05IN865\x10\t\x12\t\n\x05RU864\x10\n\x12\x0b\n\x07ISM2400\x10\x0b*\xb3\x01\n\x05MType\x12\x10\n\x0cJOIN_REQUEST\x10\x00\x12\x0f\n\x0bJOIN_ACCEPT\x10\x01\x12\x17\n\x13UNCONFIRMED_DATA_UP\x10\x02\x12\x19\n\x15UNCONFIRMED_DATA_DOWN\x10\x03\x12\x15\n\x11\x43ONFIRMED_DATA_UP\x10\x04\x12\x17\n\x13\x43ONFIRMED_DATA_DOWN\x10\x05\x12\x12\n\x0eREJOIN_REQUEST\x10\x06\x12\x0f\n\x0bPROPRIETARY\x10\x07*~\n\nMacVersion\x12\x11\n\rLORAWAN_1_0_0\x10\x00\x12\x11\n\rLORAWAN_1_0_1\x10\x01\x12\x11\n\rLORAWAN_1_0_2\x10\x02\x12\x11\n\rLORAWAN_1_0_3\x10\x03\x12\x11\n\rLORAWAN_1_0_4\x10\x04\x12\x11\n\rLORAWAN_1_1_0\x10\x05*e\n\x11RegParamsRevision\x12\x05\n\x01\x41\x10\x00\x12\x05\n\x01\x42\x10\x01\x12\x0f\n\x0bRP002_1_0_0\x10\x02\x12\x0f\n\x0bRP002_1_0_1\x10\x03\x12\x0f\n\x0bRP002_1_0_2\x10\x04\x12\x0f\n\x0bRP002_1_0_3\x10\x05*\x8e\x01\n\x0eLocationSource\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03GPS\x10\x01\x12\n\n\x06\x43ONFIG\x10\x02\x12\x15\n\x11GEO_RESOLVER_TDOA\x10\x03\x12\x15\n\x11GEO_RESOLVER_RSSI\x10\x04\x12\x15\n\x11GEO_RESOLVER_GNSS\x10\x05\x12\x15\n\x11GEO_RESOLVER_WIFI\x10\x06*+\n\x0b\x41ggregation\x12\x08\n\x04HOUR\x10\x00\x12\x07\n\x03\x44\x41Y\x10\x01\x12\t\n\x05MONTH\x10\x02*2\n\nMetricKind\x12\x0b\n\x07\x43OUNTER\x10\x00\x12\x0c\n\x08\x41\x42SOLUTE\x10\x01\x12\t\n\x05GAUGE\x10\x02*4\n\x0b\x44\x65viceClass\x12\x0b\n\x07\x43LASS_A\x10\x00\x12\x0b\n\x07\x43LASS_B\x10\x01\x12\x0b\n\x07\x43LASS_C\x10\x02\x42i\n\x11io.chirpstack.apiB\x0b\x43ommonProtoP\x01Z1github.com/chirpstack/chirpstack/api/go/v4/common\xaa\x02\x11\x43hirpstack.Commonb\x06proto3') DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"chirpstack-api/common/common.proto\x12\x06\x63ommon\x1a\x1fgoogle/protobuf/timestamp.proto\"{\n\x08Location\x12\x10\n\x08latitude\x18\x01 \x01(\x01\x12\x11\n\tlongitude\x18\x02 \x01(\x01\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x01\x12&\n\x06source\x18\x04 \x01(\x0e\x32\x16.common.LocationSource\x12\x10\n\x08\x61\x63\x63uracy\x18\x05 \x01(\x02\"1\n\x0bKeyEnvelope\x12\x11\n\tkek_label\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x65s_key\x18\x02 \x01(\x0c\"\x91\x01\n\x06Metric\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\ntimestamps\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x08\x64\x61tasets\x18\x03 \x03(\x0b\x32\x15.common.MetricDataset\x12 \n\x04kind\x18\x04 \x01(\x0e\x32\x12.common.MetricKind\",\n\rMetricDataset\x12\r\n\x05label\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"S\n\x11JoinServerContext\x12\x16\n\x0esession_key_id\x18\x01 \x01(\t\x12&\n\tapp_s_key\x18\x02 \x01(\x0b\x32\x13.common.KeyEnvelope*,\n\nModulation\x12\x08\n\x04LORA\x10\x00\x12\x07\n\x03\x46SK\x10\x01\x12\x0b\n\x07LR_FHSS\x10\x02*\xaa\x01\n\x06Region\x12\t\n\x05\x45U868\x10\x00\x12\t\n\x05US915\x10\x02\x12\t\n\x05\x43N779\x10\x03\x12\t\n\x05\x45U433\x10\x04\x12\t\n\x05\x41U915\x10\x05\x12\t\n\x05\x43N470\x10\x06\x12\t\n\x05\x41S923\x10\x07\x12\x0b\n\x07\x41S923_2\x10\x0c\x12\x0b\n\x07\x41S923_3\x10\r\x12\x0b\n\x07\x41S923_4\x10\x0e\x12\t\n\x05KR920\x10\x08\x12\t\n\x05IN865\x10\t\x12\t\n\x05RU864\x10\n\x12\x0b\n\x07ISM2400\x10\x0b*\xb3\x01\n\x05MType\x12\x10\n\x0cJOIN_REQUEST\x10\x00\x12\x0f\n\x0bJOIN_ACCEPT\x10\x01\x12\x17\n\x13UNCONFIRMED_DATA_UP\x10\x02\x12\x19\n\x15UNCONFIRMED_DATA_DOWN\x10\x03\x12\x15\n\x11\x43ONFIRMED_DATA_UP\x10\x04\x12\x17\n\x13\x43ONFIRMED_DATA_DOWN\x10\x05\x12\x12\n\x0eREJOIN_REQUEST\x10\x06\x12\x0f\n\x0bPROPRIETARY\x10\x07*~\n\nMacVersion\x12\x11\n\rLORAWAN_1_0_0\x10\x00\x12\x11\n\rLORAWAN_1_0_1\x10\x01\x12\x11\n\rLORAWAN_1_0_2\x10\x02\x12\x11\n\rLORAWAN_1_0_3\x10\x03\x12\x11\n\rLORAWAN_1_0_4\x10\x04\x12\x11\n\rLORAWAN_1_1_0\x10\x05*e\n\x11RegParamsRevision\x12\x05\n\x01\x41\x10\x00\x12\x05\n\x01\x42\x10\x01\x12\x0f\n\x0bRP002_1_0_0\x10\x02\x12\x0f\n\x0bRP002_1_0_1\x10\x03\x12\x0f\n\x0bRP002_1_0_2\x10\x04\x12\x0f\n\x0bRP002_1_0_3\x10\x05*\x8e\x01\n\x0eLocationSource\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03GPS\x10\x01\x12\n\n\x06\x43ONFIG\x10\x02\x12\x15\n\x11GEO_RESOLVER_TDOA\x10\x03\x12\x15\n\x11GEO_RESOLVER_RSSI\x10\x04\x12\x15\n\x11GEO_RESOLVER_GNSS\x10\x05\x12\x15\n\x11GEO_RESOLVER_WIFI\x10\x06*+\n\x0b\x41ggregation\x12\x08\n\x04HOUR\x10\x00\x12\x07\n\x03\x44\x41Y\x10\x01\x12\t\n\x05MONTH\x10\x02*2\n\nMetricKind\x12\x0b\n\x07\x43OUNTER\x10\x00\x12\x0c\n\x08\x41\x42SOLUTE\x10\x01\x12\t\n\x05GAUGE\x10\x02*4\n\x0b\x44\x65viceClass\x12\x0b\n\x07\x43LASS_A\x10\x00\x12\x0b\n\x07\x43LASS_B\x10\x01\x12\x0b\n\x07\x43LASS_C\x10\x02\x42i\n\x11io.chirpstack.apiB\x0b\x43ommonProtoP\x01Z1github.com/chirpstack/chirpstack/api/go/v4/common\xaa\x02\x11\x43hirpstack.Commonb\x06proto3')
_globals = globals() _globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@ -23,24 +23,24 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chirpstack_api.common.commo
if _descriptor._USE_C_DESCRIPTORS == False: if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None _globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\n\021io.chirpstack.apiB\013CommonProtoP\001Z1github.com/chirpstack/chirpstack/api/go/v4/common\252\002\021Chirpstack.Common' _globals['DESCRIPTOR']._serialized_options = b'\n\021io.chirpstack.apiB\013CommonProtoP\001Z1github.com/chirpstack/chirpstack/api/go/v4/common\252\002\021Chirpstack.Common'
_globals['_MODULATION']._serialized_start=449 _globals['_MODULATION']._serialized_start=534
_globals['_MODULATION']._serialized_end=493 _globals['_MODULATION']._serialized_end=578
_globals['_REGION']._serialized_start=496 _globals['_REGION']._serialized_start=581
_globals['_REGION']._serialized_end=666 _globals['_REGION']._serialized_end=751
_globals['_MTYPE']._serialized_start=669 _globals['_MTYPE']._serialized_start=754
_globals['_MTYPE']._serialized_end=848 _globals['_MTYPE']._serialized_end=933
_globals['_MACVERSION']._serialized_start=850 _globals['_MACVERSION']._serialized_start=935
_globals['_MACVERSION']._serialized_end=976 _globals['_MACVERSION']._serialized_end=1061
_globals['_REGPARAMSREVISION']._serialized_start=978 _globals['_REGPARAMSREVISION']._serialized_start=1063
_globals['_REGPARAMSREVISION']._serialized_end=1079 _globals['_REGPARAMSREVISION']._serialized_end=1164
_globals['_LOCATIONSOURCE']._serialized_start=1082 _globals['_LOCATIONSOURCE']._serialized_start=1167
_globals['_LOCATIONSOURCE']._serialized_end=1224 _globals['_LOCATIONSOURCE']._serialized_end=1309
_globals['_AGGREGATION']._serialized_start=1226 _globals['_AGGREGATION']._serialized_start=1311
_globals['_AGGREGATION']._serialized_end=1269 _globals['_AGGREGATION']._serialized_end=1354
_globals['_METRICKIND']._serialized_start=1271 _globals['_METRICKIND']._serialized_start=1356
_globals['_METRICKIND']._serialized_end=1321 _globals['_METRICKIND']._serialized_end=1406
_globals['_DEVICECLASS']._serialized_start=1323 _globals['_DEVICECLASS']._serialized_start=1408
_globals['_DEVICECLASS']._serialized_end=1375 _globals['_DEVICECLASS']._serialized_end=1460
_globals['_LOCATION']._serialized_start=79 _globals['_LOCATION']._serialized_start=79
_globals['_LOCATION']._serialized_end=202 _globals['_LOCATION']._serialized_end=202
_globals['_KEYENVELOPE']._serialized_start=204 _globals['_KEYENVELOPE']._serialized_start=204
@ -49,4 +49,6 @@ if _descriptor._USE_C_DESCRIPTORS == False:
_globals['_METRIC']._serialized_end=401 _globals['_METRIC']._serialized_end=401
_globals['_METRICDATASET']._serialized_start=403 _globals['_METRICDATASET']._serialized_start=403
_globals['_METRICDATASET']._serialized_end=447 _globals['_METRICDATASET']._serialized_end=447
_globals['_JOINSERVERCONTEXT']._serialized_start=449
_globals['_JOINSERVERCONTEXT']._serialized_end=532
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@ -181,3 +181,11 @@ class MetricDataset(_message.Message):
label: str label: str
data: _containers.RepeatedScalarFieldContainer[float] data: _containers.RepeatedScalarFieldContainer[float]
def __init__(self, label: _Optional[str] = ..., data: _Optional[_Iterable[float]] = ...) -> None: ... def __init__(self, label: _Optional[str] = ..., data: _Optional[_Iterable[float]] = ...) -> None: ...
class JoinServerContext(_message.Message):
__slots__ = ("session_key_id", "app_s_key")
SESSION_KEY_ID_FIELD_NUMBER: _ClassVar[int]
APP_S_KEY_FIELD_NUMBER: _ClassVar[int]
session_key_id: str
app_s_key: KeyEnvelope
def __init__(self, session_key_id: _Optional[str] = ..., app_s_key: _Optional[_Union[KeyEnvelope, _Mapping]] = ...) -> None: ...

File diff suppressed because one or more lines are too long

View File

@ -91,14 +91,6 @@ class UplinkRelayRxInfo(_message.Message):
wor_channel: int wor_channel: int
def __init__(self, dev_eui: _Optional[str] = ..., frequency: _Optional[int] = ..., dr: _Optional[int] = ..., snr: _Optional[int] = ..., rssi: _Optional[int] = ..., wor_channel: _Optional[int] = ...) -> None: ... def __init__(self, dev_eui: _Optional[str] = ..., frequency: _Optional[int] = ..., dr: _Optional[int] = ..., snr: _Optional[int] = ..., rssi: _Optional[int] = ..., wor_channel: _Optional[int] = ...) -> None: ...
class JoinServerContext(_message.Message):
__slots__ = ("session_key_id", "app_s_key")
SESSION_KEY_ID_FIELD_NUMBER: _ClassVar[int]
APP_S_KEY_FIELD_NUMBER: _ClassVar[int]
session_key_id: str
app_s_key: _common_pb2.KeyEnvelope
def __init__(self, session_key_id: _Optional[str] = ..., app_s_key: _Optional[_Union[_common_pb2.KeyEnvelope, _Mapping]] = ...) -> None: ...
class UplinkEvent(_message.Message): class UplinkEvent(_message.Message):
__slots__ = ("deduplication_id", "time", "device_info", "dev_addr", "adr", "dr", "f_cnt", "f_port", "confirmed", "data", "object", "rx_info", "tx_info", "relay_rx_info", "join_server_context") __slots__ = ("deduplication_id", "time", "device_info", "dev_addr", "adr", "dr", "f_cnt", "f_port", "confirmed", "data", "object", "rx_info", "tx_info", "relay_rx_info", "join_server_context")
DEDUPLICATION_ID_FIELD_NUMBER: _ClassVar[int] DEDUPLICATION_ID_FIELD_NUMBER: _ClassVar[int]
@ -130,8 +122,8 @@ class UplinkEvent(_message.Message):
rx_info: _containers.RepeatedCompositeFieldContainer[_gw_pb2.UplinkRxInfo] rx_info: _containers.RepeatedCompositeFieldContainer[_gw_pb2.UplinkRxInfo]
tx_info: _gw_pb2.UplinkTxInfo tx_info: _gw_pb2.UplinkTxInfo
relay_rx_info: UplinkRelayRxInfo relay_rx_info: UplinkRelayRxInfo
join_server_context: JoinServerContext join_server_context: _common_pb2.JoinServerContext
def __init__(self, deduplication_id: _Optional[str] = ..., time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., device_info: _Optional[_Union[DeviceInfo, _Mapping]] = ..., dev_addr: _Optional[str] = ..., adr: bool = ..., dr: _Optional[int] = ..., f_cnt: _Optional[int] = ..., f_port: _Optional[int] = ..., confirmed: bool = ..., data: _Optional[bytes] = ..., object: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., rx_info: _Optional[_Iterable[_Union[_gw_pb2.UplinkRxInfo, _Mapping]]] = ..., tx_info: _Optional[_Union[_gw_pb2.UplinkTxInfo, _Mapping]] = ..., relay_rx_info: _Optional[_Union[UplinkRelayRxInfo, _Mapping]] = ..., join_server_context: _Optional[_Union[JoinServerContext, _Mapping]] = ...) -> None: ... def __init__(self, deduplication_id: _Optional[str] = ..., time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., device_info: _Optional[_Union[DeviceInfo, _Mapping]] = ..., dev_addr: _Optional[str] = ..., adr: bool = ..., dr: _Optional[int] = ..., f_cnt: _Optional[int] = ..., f_port: _Optional[int] = ..., confirmed: bool = ..., data: _Optional[bytes] = ..., object: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., rx_info: _Optional[_Iterable[_Union[_gw_pb2.UplinkRxInfo, _Mapping]]] = ..., tx_info: _Optional[_Union[_gw_pb2.UplinkTxInfo, _Mapping]] = ..., relay_rx_info: _Optional[_Union[UplinkRelayRxInfo, _Mapping]] = ..., join_server_context: _Optional[_Union[_common_pb2.JoinServerContext, _Mapping]] = ...) -> None: ...
class JoinEvent(_message.Message): class JoinEvent(_message.Message):
__slots__ = ("deduplication_id", "time", "device_info", "dev_addr", "relay_rx_info", "join_server_context") __slots__ = ("deduplication_id", "time", "device_info", "dev_addr", "relay_rx_info", "join_server_context")
@ -146,8 +138,8 @@ class JoinEvent(_message.Message):
device_info: DeviceInfo device_info: DeviceInfo
dev_addr: str dev_addr: str
relay_rx_info: UplinkRelayRxInfo relay_rx_info: UplinkRelayRxInfo
join_server_context: JoinServerContext join_server_context: _common_pb2.JoinServerContext
def __init__(self, deduplication_id: _Optional[str] = ..., time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., device_info: _Optional[_Union[DeviceInfo, _Mapping]] = ..., dev_addr: _Optional[str] = ..., relay_rx_info: _Optional[_Union[UplinkRelayRxInfo, _Mapping]] = ..., join_server_context: _Optional[_Union[JoinServerContext, _Mapping]] = ...) -> None: ... def __init__(self, deduplication_id: _Optional[str] = ..., time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., device_info: _Optional[_Union[DeviceInfo, _Mapping]] = ..., dev_addr: _Optional[str] = ..., relay_rx_info: _Optional[_Union[UplinkRelayRxInfo, _Mapping]] = ..., join_server_context: _Optional[_Union[_common_pb2.JoinServerContext, _Mapping]] = ...) -> None: ...
class AckEvent(_message.Message): class AckEvent(_message.Message):
__slots__ = ("deduplication_id", "time", "device_info", "queue_item_id", "acknowledged", "f_cnt_down") __slots__ = ("deduplication_id", "time", "device_info", "queue_item_id", "acknowledged", "f_cnt_down")

2
api/rust/Cargo.toml vendored
View File

@ -12,6 +12,7 @@ edition = "2021"
default = ["api", "json"] default = ["api", "json"]
api = ["tonic/transport", "tonic-build/transport", "tokio"] api = ["tonic/transport", "tonic-build/transport", "tokio"]
json = ["pbjson", "pbjson-types", "serde"] json = ["pbjson", "pbjson-types", "serde"]
diesel = ["dep:diesel"]
internal = [] internal = []
[dependencies] [dependencies]
@ -25,6 +26,7 @@ tokio = { version = "1.32", features = ["macros"], optional = true }
pbjson = { version = "0.6", optional = true } pbjson = { version = "0.6", optional = true }
pbjson-types = { version = "0.6", optional = true } pbjson-types = { version = "0.6", optional = true }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
diesel = { version = "2.1", features = ["postgres_backend"], optional = true }
[build-dependencies] [build-dependencies]
tonic-build = { version = "0.10", features = ["prost"], default-features = false } tonic-build = { version = "0.10", features = ["prost"], default-features = false }

14
api/rust/build.rs vendored
View File

@ -73,13 +73,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
// internal // internal
tonic_build::configure() {
let mut builder = tonic_build::configure()
.out_dir(out_dir.join("internal")) .out_dir(out_dir.join("internal"))
.file_descriptor_set_path(out_dir.join("internal").join("proto_descriptor.bin")) .file_descriptor_set_path(out_dir.join("internal").join("proto_descriptor.bin"))
.compile_well_known_types(true) .compile_well_known_types(true)
.extern_path(".google.protobuf", well_known_types_path) .extern_path(".google.protobuf", well_known_types_path)
.extern_path(".common", "crate::common") .extern_path(".common", "crate::common");
.compile(
#[cfg(feature = "diesel")]
{
builder = builder.message_attribute("internal.DeviceSession", "#[derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)] #[diesel(sql_type = diesel::sql_types::Binary)]");
}
builder.compile(
&[cs_dir &[cs_dir
.join("internal") .join("internal")
.join("internal.proto") .join("internal.proto")
@ -90,6 +97,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
proto_dir.join("google").to_str().unwrap(), proto_dir.join("google").to_str().unwrap(),
], ],
)?; )?;
}
#[cfg(feature = "json")] #[cfg(feature = "json")]
{ {

View File

@ -418,6 +418,12 @@ message GetDeviceActivationRequest {
message GetDeviceActivationResponse { message GetDeviceActivationResponse {
// Device activation object. // Device activation object.
DeviceActivation device_activation = 1; DeviceActivation device_activation = 1;
// Join-Server context.
// A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application.
common.JoinServerContext join_server_context = 2;
} }
message GetRandomDevAddrRequest { message GetRandomDevAddrRequest {

View File

@ -213,3 +213,12 @@ enum DeviceClass {
// Class-C. // Class-C.
CLASS_C = 2; CLASS_C = 2;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
KeyEnvelope app_s_key = 2;
}

View File

@ -114,15 +114,6 @@ message UplinkRelayRxInfo {
uint32 wor_channel = 6; uint32 wor_channel = 6;
} }
// Join-Server context.
message JoinServerContext {
// Session-key ID.
string session_key_id = 1;
// AppSKey envelope.
common.KeyEnvelope app_s_key = 2;
}
// UplinkEvent is the message sent when an uplink payload has been received. // UplinkEvent is the message sent when an uplink payload has been received.
message UplinkEvent { message UplinkEvent {
// Deduplication ID (UUID). // Deduplication ID (UUID).
@ -172,7 +163,7 @@ message UplinkEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 15; common.JoinServerContext join_server_context = 15;
} }
// JoinEvent is the message sent when a device joined the network. // JoinEvent is the message sent when a device joined the network.
@ -197,7 +188,7 @@ message JoinEvent {
// A non-empty value indicatest that ChirpStack does not have access to // A non-empty value indicatest that ChirpStack does not have access to
// the AppSKey and that the encryption / decryption of the payloads is // the AppSKey and that the encryption / decryption of the payloads is
// the responsibility of the end-application. // the responsibility of the end-application.
JoinServerContext join_server_context = 6; common.JoinServerContext join_server_context = 6;
} }
// AckEvent is the message sent when a confirmation on a confirmed downlink // AckEvent is the message sent when a confirmation on a confirmed downlink

View File

@ -7,15 +7,9 @@ import "gw/gw.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
message DeviceSession { message DeviceSession {
// Device EUI.
bytes dev_eui = 1;
// Device address. // Device address.
bytes dev_addr = 2; bytes dev_addr = 2;
// Join EUI.
bytes join_eui = 3;
// LoRaWAN mac-version. // LoRaWAN mac-version.
common.MacVersion mac_version = 4; common.MacVersion mac_version = 4;

View File

@ -2,6 +2,14 @@ include!(concat!(env!("OUT_DIR"), "/internal/internal.rs"));
#[cfg(feature = "json")] #[cfg(feature = "json")]
include!(concat!(env!("OUT_DIR"), "/internal/internal.serde.rs")); include!(concat!(env!("OUT_DIR"), "/internal/internal.serde.rs"));
#[cfg(feature = "diesel")]
use std::io::Cursor;
#[cfg(feature = "diesel")]
use diesel::{backend::Backend, deserialize, serialize, sql_types::Binary};
#[cfg(feature = "diesel")]
use prost::Message;
impl DeviceSession { impl DeviceSession {
pub fn get_a_f_cnt_down(&self) -> u32 { pub fn get_a_f_cnt_down(&self) -> u32 {
if self.mac_version().to_string().starts_with("1.0") { if self.mac_version().to_string().starts_with("1.0") {
@ -23,3 +31,28 @@ impl DeviceSession {
} }
} }
} }
#[cfg(feature = "diesel")]
impl<ST, DB> deserialize::FromSql<ST, DB> for DeviceSession
where
DB: Backend,
*const [u8]: deserialize::FromSql<ST, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> deserialize::Result<Self> {
let bytes = <Vec<u8> as deserialize::FromSql<ST, DB>>::from_sql(value)?;
Ok(DeviceSession::decode(&mut Cursor::new(bytes))?)
}
}
#[cfg(feature = "diesel")]
impl serialize::ToSql<Binary, diesel::pg::Pg> for DeviceSession
where
[u8]: serialize::ToSql<Binary, diesel::pg::Pg>,
{
fn to_sql<'b>(&self, out: &mut serialize::Output<'b, '_, diesel::pg::Pg>) -> serialize::Result {
<[u8] as serialize::ToSql<Binary, diesel::pg::Pg>>::to_sql(
&self.encode_to_vec(),
&mut out.reborrow(),
)
}
}

View File

@ -49,7 +49,7 @@ tracing-subscriber = { version = "0.3", features = [
], default-features = true } ], default-features = true }
# ChirpStack API definitions # ChirpStack API definitions
chirpstack_api = { path = "../api/rust", features = ["default", "internal"] } chirpstack_api = { path = "../api/rust", features = ["default", "internal", "diesel"] }
lrwn = { path = "../lrwn", features = ["serde", "diesel", "regions", "crypto"] } lrwn = { path = "../lrwn", features = ["serde", "diesel", "regions", "crypto"] }
backend = { path = "../backend" } backend = { path = "../backend" }

View File

@ -0,0 +1,6 @@
drop index idx_device_dev_addr;
drop index idx_device_secondary_dev_addr;
alter table device
drop column secondary_dev_addr,
drop column device_session;

View File

@ -0,0 +1,6 @@
alter table device
add column secondary_dev_addr bytea,
add column device_session bytea;
create index idx_device_dev_addr on device (dev_addr);
create index idx_device_secondary_dev_addr on device (secondary_dev_addr);

View File

@ -18,7 +18,7 @@ use crate::backend::{joinserver, keywrap, roaming};
use crate::downlink::data_fns; use crate::downlink::data_fns;
use crate::helpers::errors::PrintFullError; use crate::helpers::errors::PrintFullError;
use crate::storage::{ use crate::storage::{
device_session, error::Error as StorageError, get_async_redis_conn, passive_roaming, redis_key, device, error::Error as StorageError, get_async_redis_conn, passive_roaming, redis_key,
}; };
use crate::uplink::{ use crate::uplink::{
data_sns, error::Error as UplinkError, helpers, join_sns, RoamingMetaData, UplinkFrameSet, data_sns, error::Error as UplinkError, helpers, join_sns, RoamingMetaData, UplinkFrameSet,
@ -312,9 +312,10 @@ async fn _handle_pr_start_req_data(
}; };
// get device-session // get device-session
let ds = device_session::get_for_phypayload(&mut ufs.phy_payload, ufs.dr, ufs.ch as u8).await?; let d = device::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 pr_lifetime = roaming::get_passive_roaming_lifetime(sender_id)?;
let kek_label = roaming::get_passive_roaming_kek_label(sender_id)?; let kek_label = roaming::get_passive_roaming_kek_label(sender_id)?;
let ds = d.get_device_session()?;
let nwk_s_key = if ds.mac_version().to_string().starts_with("1.0") { let nwk_s_key = if ds.mac_version().to_string().starts_with("1.0") {
Some(keywrap::wrap( Some(keywrap::wrap(
@ -343,7 +344,7 @@ async fn _handle_pr_start_req_data(
base: pl base: pl
.base .base
.to_base_payload_result(backend::ResultCode::Success, ""), .to_base_payload_result(backend::ResultCode::Success, ""),
dev_eui: ds.dev_eui.clone(), dev_eui: d.dev_eui.to_vec(),
lifetime: if pr_lifetime.is_zero() { lifetime: if pr_lifetime.is_zero() {
None None
} else { } else {

View File

@ -15,10 +15,11 @@ use lrwn::{AES128Key, DevAddr, EUI64};
use super::auth::validator; use super::auth::validator;
use super::error::ToStatus; use super::error::ToStatus;
use super::helpers::{self, FromProto, ToProto}; use super::helpers::{self, FromProto, ToProto};
use crate::storage::error::Error;
use crate::storage::{ use crate::storage::{
device::{self, DeviceClass}, device::{self, DeviceClass},
device_keys, device_profile, device_queue, device_session, fields, metrics, device_keys, device_profile, device_queue,
error::Error as StorageError,
fields, metrics,
}; };
use crate::{codec, devaddr::get_random_dev_addr}; use crate::{codec, devaddr::get_random_dev_addr};
@ -514,7 +515,6 @@ impl DeviceService for Device {
let mut ds = internal::DeviceSession { let mut ds = internal::DeviceSession {
region_config_id: "".to_string(), region_config_id: "".to_string(),
dev_eui: dev_eui.to_vec(),
dev_addr: dev_addr.to_vec(), dev_addr: dev_addr.to_vec(),
mac_version: dp.mac_version.to_proto().into(), mac_version: dp.mac_version.to_proto().into(),
s_nwk_s_int_key: s_nwk_s_int_key.to_vec(), s_nwk_s_int_key: s_nwk_s_int_key.to_vec(),
@ -532,7 +532,14 @@ impl DeviceService for Device {
}; };
dp.reset_session_to_boot_params(&mut ds); dp.reset_session_to_boot_params(&mut ds);
device_session::save(&ds).await.map_err(|e| e.status())?; let mut device_changeset = device::DeviceChangeset {
device_session: Some(Some(ds)),
dev_addr: Some(Some(dev_addr)),
secondary_dev_addr: Some(None),
..Default::default()
};
// Flush queue (if configured).
if dp.flush_queue_on_activate { if dp.flush_queue_on_activate {
device_queue::flush_for_dev_eui(&dev_eui) device_queue::flush_for_dev_eui(&dev_eui)
.await .await
@ -541,14 +548,14 @@ impl DeviceService for Device {
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C. Change the class here for LoRaWAN 1.0 devices. // LoRaWAN 1.1 devices send a mac-command when changing to Class-C. Change the class here for LoRaWAN 1.0 devices.
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") { if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
let _ = device::set_enabled_class(&dev_eui, DeviceClass::C) device_changeset.enabled_class = Some(DeviceClass::C);
.await
.map_err(|e| e.status())?;
} else { } else {
let _ = device::set_enabled_class(&dev_eui, DeviceClass::A) device_changeset.enabled_class = Some(DeviceClass::A);
}
device::partial_update(dev_eui, &device_changeset)
.await .await
.map_err(|e| e.status())?; .map_err(|e| e.status())?;
}
let mut resp = Response::new(()); let mut resp = Response::new(());
resp.metadata_mut() resp.metadata_mut()
@ -574,7 +581,16 @@ impl DeviceService for Device {
device_queue::flush_for_dev_eui(&dev_eui) device_queue::flush_for_dev_eui(&dev_eui)
.await .await
.map_err(|e| e.status())?; .map_err(|e| e.status())?;
device_session::delete(&dev_eui)
device::partial_update(
dev_eui,
&device::DeviceChangeset {
dev_addr: Some(None),
secondary_dev_addr: Some(None),
device_session: Some(None),
..Default::default()
},
)
.await .await
.map_err(|e| e.status())?; .map_err(|e| e.status())?;
@ -599,24 +615,24 @@ impl DeviceService for Device {
) )
.await?; .await?;
let ds = match device_session::get(&dev_eui).await { let d = device::get(&dev_eui).await.map_err(|e| e.status())?;
let ds = match d.get_device_session() {
Ok(v) => v, Ok(v) => v,
Err(e) => match e { Err(StorageError::NotFound(_)) => {
Error::NotFound(_) => {
return Ok(Response::new(api::GetDeviceActivationResponse { return Ok(Response::new(api::GetDeviceActivationResponse {
device_activation: None, device_activation: None,
join_server_context: None,
})); }));
} }
_ => { Err(e) => {
return Err(e.status()); return Err(e.status());
} }
},
}; };
let mut resp = Response::new(api::GetDeviceActivationResponse { let mut resp = Response::new(api::GetDeviceActivationResponse {
device_activation: Some(api::DeviceActivation { device_activation: Some(api::DeviceActivation {
dev_eui: hex::encode(&ds.dev_eui), dev_eui: d.dev_eui.to_string(),
dev_addr: hex::encode(&ds.dev_addr), dev_addr: d.get_dev_addr().map_err(|e| e.status())?.to_string(),
app_s_key: match &ds.app_s_key { app_s_key: match &ds.app_s_key {
Some(v) => hex::encode(&v.aes_key), Some(v) => hex::encode(&v.aes_key),
None => "".to_string(), None => "".to_string(),
@ -628,6 +644,26 @@ impl DeviceService for Device {
n_f_cnt_down: ds.n_f_cnt_down, n_f_cnt_down: ds.n_f_cnt_down,
a_f_cnt_down: ds.a_f_cnt_down, a_f_cnt_down: ds.a_f_cnt_down,
}), }),
join_server_context: if !ds.js_session_key_id.is_empty() {
Some(common::JoinServerContext {
app_s_key: None,
session_key_id: hex::encode(&ds.js_session_key_id),
})
} else if let Some(app_s_key) = &ds.app_s_key {
if !app_s_key.kek_label.is_empty() {
Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope {
kek_label: app_s_key.kek_label.clone(),
aes_key: app_s_key.aes_key.clone(),
}),
session_key_id: "".into(),
})
} else {
None
}
} else {
None
},
}); });
resp.metadata_mut() resp.metadata_mut()
.insert("x-log-dev_eui", req.dev_eui.parse().unwrap()); .insert("x-log-dev_eui", req.dev_eui.parse().unwrap());
@ -1160,7 +1196,14 @@ impl DeviceService for Device {
) )
.await?; .await?;
let ds = device_session::get(&dev_eui).await.unwrap_or_default(); let d = device::get(&dev_eui).await.map_err(|e| e.status())?;
let ds = match d.get_device_session() {
Ok(v) => v.clone(),
Err(StorageError::NotFound(_)) => Default::default(),
Err(e) => {
return Err(e.status());
}
};
let max_f_cnt_down_queue = device_queue::get_max_f_cnt_down(dev_eui) let max_f_cnt_down_queue = device_queue::get_max_f_cnt_down(dev_eui)
.await .await
@ -1182,7 +1225,7 @@ pub mod test {
use super::*; use super::*;
use crate::api::auth::validator::RequestValidator; use crate::api::auth::validator::RequestValidator;
use crate::api::auth::AuthID; use crate::api::auth::AuthID;
use crate::storage::{application, tenant, user}; use crate::storage::{application, device, tenant, user};
use crate::test; use crate::test;
use lrwn::NetID; use lrwn::NetID;
@ -1435,6 +1478,15 @@ pub mod test {
); );
let _ = service.activate(activate_req).await.unwrap(); let _ = service.activate(activate_req).await.unwrap();
// test that the device DevAddr was set.
let dev = device::get(&EUI64::from_str("0102030405060708").unwrap())
.await
.unwrap();
assert_eq!(
DevAddr::from_str("04030201").unwrap(),
dev.dev_addr.unwrap()
);
// get activation // get activation
let get_activation_req = get_request( let get_activation_req = get_request(
&u.id, &u.id,
@ -1488,6 +1540,72 @@ pub mod test {
let get_activation_resp = service.get_activation(get_activation_req).await.unwrap(); let get_activation_resp = service.get_activation(get_activation_req).await.unwrap();
assert!(get_activation_resp.get_ref().device_activation.is_none()); assert!(get_activation_resp.get_ref().device_activation.is_none());
// test get activation with JS session-key ID.
device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
dev_addr: Some(Some(DevAddr::from_be_bytes([1, 2, 3, 4]))),
device_session: Some(Some(internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4],
js_session_key_id: vec![8, 7, 6, 5, 4, 3, 2, 1],
..Default::default()
})),
..Default::default()
},
)
.await
.unwrap();
let get_activation_req = get_request(
&u.id,
api::GetDeviceActivationRequest {
dev_eui: "0102030405060708".into(),
},
);
let get_activation_resp = service.get_activation(get_activation_req).await.unwrap();
assert_eq!(
Some(common::JoinServerContext {
session_key_id: "0807060504030201".into(),
app_s_key: None,
}),
get_activation_resp.get_ref().join_server_context
);
// test activation with AppSKey key-envelope.
device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4],
app_s_key: Some(common::KeyEnvelope {
kek_label: "test-key".into(),
aes_key: vec![8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1],
}),
..Default::default()
})),
..Default::default()
},
)
.await
.unwrap();
let get_activation_req = get_request(
&u.id,
api::GetDeviceActivationRequest {
dev_eui: "0102030405060708".into(),
},
);
let get_activation_resp = service.get_activation(get_activation_req).await.unwrap();
assert_eq!(
Some(common::JoinServerContext {
session_key_id: "".into(),
app_s_key: Some(common::KeyEnvelope {
kek_label: "test-key".into(),
aes_key: vec![8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1],
}),
}),
get_activation_resp.get_ref().join_server_context
);
// get random dev addr // get random dev addr
let get_random_dev_addr_req = get_request( let get_random_dev_addr_req = get_request(
&u.id, &u.id,

View File

@ -0,0 +1,56 @@
use anyhow::Result;
use diesel::prelude::*;
use diesel_async::RunQueryDsl;
use tracing::{debug, info};
use crate::storage::{self, device_session, error::Error, get_async_db_conn, schema::device};
use lrwn::{DevAddr, EUI64};
pub async fn run() -> Result<()> {
storage::setup().await?;
info!("Migrating device-sessions from Redis to PostgreSQL");
info!("Getting DevEUIs from PostgreSQL without device-session");
let dev_euis: Vec<EUI64> = device::dsl::device
.select(device::dsl::dev_eui)
.filter(device::dsl::device_session.is_null())
.load(&mut get_async_db_conn().await?)
.await?;
info!(
"There are {} devices in PostgreSQL without device-session set",
dev_euis.len()
);
for dev_eui in &dev_euis {
debug!(dev_eui = %dev_eui, "Migrating device-session");
let ds = match device_session::get(dev_eui).await {
Ok(v) => v,
Err(e) => match e {
Error::NotFound(_) => {
debug!(dev_eui = %dev_eui, "Device does not have a device-session");
continue;
}
_ => {
return Err(anyhow::Error::new(e));
}
},
};
storage::device::partial_update(
*dev_eui,
&storage::device::DeviceChangeset {
dev_addr: Some(Some(DevAddr::from_slice(&ds.dev_addr)?)),
device_session: Some(Some(ds)),
..Default::default()
},
)
.await?;
debug!(dev_eui = %dev_eui, "Device-session migrated");
}
Ok(())
}

View File

@ -1,5 +1,6 @@
pub mod configfile; pub mod configfile;
pub mod create_api_key; pub mod create_api_key;
pub mod import_legacy_lorawan_devices_repository; pub mod import_legacy_lorawan_devices_repository;
pub mod migrate_ds_to_pg;
pub mod print_ds; pub mod print_ds;
pub mod root; pub mod root;

View File

@ -1,14 +1,14 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use crate::storage; use crate::storage;
use crate::storage::device_session; use crate::storage::device;
use lrwn::EUI64; use lrwn::EUI64;
pub async fn run(dev_eui: &EUI64) -> Result<()> { pub async fn run(dev_eui: &EUI64) -> Result<()> {
storage::setup().await.context("Setup storage")?; storage::setup().await.context("Setup storage")?;
let ds = device_session::get(dev_eui)
.await let d = device::get(dev_eui).await.context("Get device")?;
.context("Get device-session")?; let ds = d.get_device_session()?;
let json = serde_json::to_string_pretty(&ds)?; let json = serde_json::to_string_pretty(&ds)?;
println!("{}", json); println!("{}", json);

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,6 @@ pub struct JoinAccept<'a> {
relay_context: Option<&'a RelayContext>, relay_context: Option<&'a RelayContext>,
tenant: &'a tenant::Tenant, tenant: &'a tenant::Tenant,
device: &'a device::Device, device: &'a device::Device,
device_session: &'a internal::DeviceSession,
join_accept: &'a PhyPayload, join_accept: &'a PhyPayload,
network_conf: config::RegionNetwork, network_conf: config::RegionNetwork,
region_conf: Arc<Box<dyn lrwn::region::Region + Sync + Send>>, region_conf: Arc<Box<dyn lrwn::region::Region + Sync + Send>>,
@ -36,20 +35,12 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet, ufs: &UplinkFrameSet,
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
device: &device::Device, device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload, join_accept: &PhyPayload,
) -> Result<()> { ) -> Result<()> {
let downlink_id: u32 = rand::thread_rng().gen(); let downlink_id: u32 = rand::thread_rng().gen();
let span = span!(Level::INFO, "join_accept", downlink_id = downlink_id); let span = span!(Level::INFO, "join_accept", downlink_id = downlink_id);
let fut = JoinAccept::_handle( let fut = JoinAccept::_handle(downlink_id, ufs, tenant, device, join_accept);
downlink_id,
ufs,
tenant,
device,
device_session,
join_accept,
);
fut.instrument(span).await fut.instrument(span).await
} }
@ -58,7 +49,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet, ufs: &UplinkFrameSet,
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
device: &device::Device, device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload, join_accept: &PhyPayload,
) -> Result<()> { ) -> Result<()> {
let downlink_id: u32 = rand::thread_rng().gen(); let downlink_id: u32 = rand::thread_rng().gen();
@ -68,15 +58,8 @@ impl JoinAccept<'_> {
downlink_id = downlink_id downlink_id = downlink_id
); );
let fut = JoinAccept::_handle_relayed( let fut =
downlink_id, JoinAccept::_handle_relayed(downlink_id, relay_ctx, ufs, tenant, device, join_accept);
relay_ctx,
ufs,
tenant,
device,
device_session,
join_accept,
);
fut.instrument(span).await fut.instrument(span).await
} }
@ -85,7 +68,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet, ufs: &UplinkFrameSet,
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
device: &device::Device, device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload, join_accept: &PhyPayload,
) -> Result<()> { ) -> Result<()> {
let mut ctx = JoinAccept { let mut ctx = JoinAccept {
@ -93,7 +75,6 @@ impl JoinAccept<'_> {
relay_context: None, relay_context: None,
tenant, tenant,
device, device,
device_session,
join_accept, join_accept,
network_conf: config::get_region_network(&ufs.region_config_id)?, network_conf: config::get_region_network(&ufs.region_config_id)?,
region_conf: region::get(&ufs.region_config_id)?, region_conf: region::get(&ufs.region_config_id)?,
@ -122,7 +103,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet, ufs: &UplinkFrameSet,
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
device: &device::Device, device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload, join_accept: &PhyPayload,
) -> Result<()> { ) -> Result<()> {
let mut ctx = JoinAccept { let mut ctx = JoinAccept {
@ -130,7 +110,6 @@ impl JoinAccept<'_> {
relay_context: Some(relay_ctx), relay_context: Some(relay_ctx),
tenant, tenant,
device, device,
device_session,
join_accept, join_accept,
network_conf: config::get_region_network(&ufs.region_config_id)?, network_conf: config::get_region_network(&ufs.region_config_id)?,
region_conf: region::get(&ufs.region_config_id)?, region_conf: region::get(&ufs.region_config_id)?,
@ -302,6 +281,7 @@ impl JoinAccept<'_> {
let gw_down = self.downlink_gateway.as_ref().unwrap(); let gw_down = self.downlink_gateway.as_ref().unwrap();
let relay_ctx = self.relay_context.unwrap(); let relay_ctx = self.relay_context.unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let mut tx_info = chirpstack_api::gw::DownlinkTxInfo { let mut tx_info = chirpstack_api::gw::DownlinkTxInfo {
board: gw_down.board, board: gw_down.board,
@ -311,7 +291,7 @@ impl JoinAccept<'_> {
}; };
// Get RX1 DR offset. // Get RX1 DR offset.
let rx1_dr_offset = relay_ctx.device_session.rx1_dr_offset as usize; let rx1_dr_offset = relay_ds.rx1_dr_offset as usize;
// get RX1 DR. // get RX1 DR.
let rx1_dr_index = self let rx1_dr_index = self
@ -337,8 +317,8 @@ impl JoinAccept<'_> {
} }
// Set timestamp. // Set timestamp.
let delay = if relay_ctx.device_session.rx1_delay > 0 { let delay = if relay_ds.rx1_delay > 0 {
Duration::from_secs(relay_ctx.device_session.rx1_delay as u64) Duration::from_secs(relay_ds.rx1_delay as u64)
} else { } else {
self.region_conf.get_defaults().rx1_delay self.region_conf.get_defaults().rx1_delay
}; };
@ -415,9 +395,10 @@ impl JoinAccept<'_> {
let gw_down = self.downlink_gateway.as_ref().unwrap(); let gw_down = self.downlink_gateway.as_ref().unwrap();
let relay_ctx = self.relay_context.unwrap(); let relay_ctx = self.relay_context.unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
// Get frequency. // Get frequency.
let frequency = relay_ctx.device_session.rx2_frequency; let frequency = relay_ds.rx2_frequency;
let mut tx_info = chirpstack_api::gw::DownlinkTxInfo { let mut tx_info = chirpstack_api::gw::DownlinkTxInfo {
board: gw_down.board, board: gw_down.board,
@ -428,7 +409,7 @@ impl JoinAccept<'_> {
}; };
// get RX2 DR // get RX2 DR
let rx2_dr_index = relay_ctx.device_session.rx2_dr as u8; let rx2_dr_index = relay_ds.rx2_dr as u8;
let rx2_dr = self.region_conf.get_data_rate(rx2_dr_index)?; let rx2_dr = self.region_conf.get_data_rate(rx2_dr_index)?;
// set DR to tx_info // set DR to tx_info
@ -444,8 +425,8 @@ impl JoinAccept<'_> {
} }
// Set timestamp. // Set timestamp.
let delay = if relay_ctx.device_session.rx1_delay > 0 { let delay = if relay_ds.rx1_delay > 0 {
Duration::from_secs(relay_ctx.device_session.rx1_delay as u64 + 1) Duration::from_secs(relay_ds.rx1_delay as u64 + 1)
} else { } else {
self.region_conf.get_defaults().rx2_delay self.region_conf.get_defaults().rx2_delay
}; };
@ -481,6 +462,7 @@ impl JoinAccept<'_> {
trace!("Setting ForwardDownlinkReq frame"); trace!("Setting ForwardDownlinkReq frame");
let relay_ctx = self.relay_context.as_ref().unwrap(); let relay_ctx = self.relay_context.as_ref().unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let mut relay_phy = lrwn::PhyPayload { let mut relay_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR { mhdr: lrwn::MHDR {
@ -489,16 +471,11 @@ impl JoinAccept<'_> {
}, },
payload: lrwn::Payload::MACPayload(lrwn::MACPayload { payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
fhdr: lrwn::FHDR { fhdr: lrwn::FHDR {
devaddr: lrwn::DevAddr::from_slice(&relay_ctx.device_session.dev_addr)?, devaddr: relay_ctx.device.get_dev_addr()?,
f_cnt: if relay_ctx f_cnt: if relay_ds.mac_version().to_string().starts_with("1.0") {
.device_session relay_ds.n_f_cnt_down
.mac_version()
.to_string()
.starts_with("1.0")
{
relay_ctx.device_session.n_f_cnt_down
} else { } else {
relay_ctx.device_session.a_f_cnt_down relay_ds.a_f_cnt_down
}, },
f_ctrl: lrwn::FCtrl { f_ctrl: lrwn::FCtrl {
adr: !self.network_conf.adr_disabled, adr: !self.network_conf.adr_disabled,
@ -517,17 +494,15 @@ impl JoinAccept<'_> {
mic: None, mic: None,
}; };
relay_phy.encrypt_frm_payload(&lrwn::AES128Key::from_slice( relay_phy.encrypt_frm_payload(&lrwn::AES128Key::from_slice(&relay_ds.nwk_s_enc_key)?)?;
&relay_ctx.device_session.nwk_s_enc_key,
)?)?;
// Set MIC. // Set MIC.
// If this is an ACK, then FCntUp has already been incremented by one. If // If this is an ACK, then FCntUp has already been incremented by one. If
// this is not an ACK, then DownlinkDataMIC will zero out ConfFCnt. // this is not an ACK, then DownlinkDataMIC will zero out ConfFCnt.
relay_phy.set_downlink_data_mic( relay_phy.set_downlink_data_mic(
relay_ctx.device_session.mac_version().from_proto(), relay_ds.mac_version().from_proto(),
relay_ctx.device_session.f_cnt_up - 1, relay_ds.f_cnt_up - 1,
&lrwn::AES128Key::from_slice(&relay_ctx.device_session.s_nwk_s_int_key)?, &lrwn::AES128Key::from_slice(&relay_ds.s_nwk_s_int_key)?,
)?; )?;
let relay_phy_b = relay_phy.to_vec()?; let relay_phy_b = relay_phy.to_vec()?;
@ -551,12 +526,13 @@ impl JoinAccept<'_> {
async fn save_downlink_frame(&self) -> Result<()> { async fn save_downlink_frame(&self) -> Result<()> {
trace!("Saving downlink frame"); trace!("Saving downlink frame");
let ds = self.device.get_device_session()?;
let df = chirpstack_api::internal::DownlinkFrame { let df = chirpstack_api::internal::DownlinkFrame {
dev_eui: self.device.dev_eui.to_be_bytes().to_vec(), dev_eui: self.device.dev_eui.to_be_bytes().to_vec(),
downlink_id: self.downlink_frame.downlink_id, downlink_id: self.downlink_frame.downlink_id,
downlink_frame: Some(self.downlink_frame.clone()), downlink_frame: Some(self.downlink_frame.clone()),
nwk_s_enc_key: self.device_session.nwk_s_enc_key.clone(), nwk_s_enc_key: ds.nwk_s_enc_key.clone(),
..Default::default() ..Default::default()
}; };
@ -571,14 +547,15 @@ impl JoinAccept<'_> {
trace!("Saving ForwardDownlinkReq frame"); trace!("Saving ForwardDownlinkReq frame");
let relay_ctx = self.relay_context.as_ref().unwrap(); let relay_ctx = self.relay_context.as_ref().unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let df = chirpstack_api::internal::DownlinkFrame { let df = chirpstack_api::internal::DownlinkFrame {
dev_eui: relay_ctx.device.dev_eui.to_be_bytes().to_vec(), dev_eui: relay_ctx.device.dev_eui.to_be_bytes().to_vec(),
downlink_id: self.downlink_frame.downlink_id, downlink_id: self.downlink_frame.downlink_id,
downlink_frame: Some(self.downlink_frame.clone()), downlink_frame: Some(self.downlink_frame.clone()),
nwk_s_enc_key: relay_ctx.device_session.nwk_s_enc_key.clone(), nwk_s_enc_key: relay_ds.nwk_s_enc_key.clone(),
a_f_cnt_down: relay_ctx.device_session.get_a_f_cnt_down(), a_f_cnt_down: relay_ds.get_a_f_cnt_down(),
n_f_cnt_down: relay_ctx.device_session.n_f_cnt_down, n_f_cnt_down: relay_ds.n_f_cnt_down,
..Default::default() ..Default::default()
}; };

View File

@ -9,7 +9,9 @@ use crate::api::helpers::ToProto;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_profile, device_queue, device_session, downlink_frame, multicast, tenant, device_profile, device_queue, downlink_frame,
helpers::get_all_device_data,
multicast, tenant,
}; };
use crate::{integration, stream}; use crate::{integration, stream};
use chirpstack_api::{common, gw, integration as integration_pb, internal, stream as stream_pb}; use chirpstack_api::{common, gw, integration as integration_pb, internal, stream as stream_pb};
@ -23,8 +25,6 @@ pub struct TxAck {
downlink_frame_item: Option<gw::DownlinkFrameItem>, downlink_frame_item: Option<gw::DownlinkFrameItem>,
phy_payload: Option<PhyPayload>, phy_payload: Option<PhyPayload>,
phy_payload_relayed: Option<PhyPayload>, phy_payload_relayed: Option<PhyPayload>,
device_session: Option<internal::DeviceSession>,
device_session_relayed: Option<internal::DeviceSession>,
tenant: Option<tenant::Tenant>, tenant: Option<tenant::Tenant>,
tenant_relayed: Option<tenant::Tenant>, tenant_relayed: Option<tenant::Tenant>,
application: Option<application::Application>, application: Option<application::Application>,
@ -66,8 +66,6 @@ impl TxAck {
downlink_frame_item: None, downlink_frame_item: None,
phy_payload: None, phy_payload: None,
phy_payload_relayed: None, phy_payload_relayed: None,
device_session: None,
device_session_relayed: None,
tenant: None, tenant: None,
tenant_relayed: None, tenant_relayed: None,
application: None, application: None,
@ -88,10 +86,7 @@ impl TxAck {
if ctx.is_error() { if ctx.is_error() {
if ctx.is_application_payload() || ctx.is_mac_only_downlink() { if ctx.is_application_payload() || ctx.is_mac_only_downlink() {
ctx.get_device().await?; ctx.get_device_data().await?;
ctx.get_device_profile().await?;
ctx.get_application().await?;
ctx.get_tenant().await?;
ctx.log_tx_ack_error().await?; ctx.log_tx_ack_error().await?;
} }
@ -99,12 +94,10 @@ impl TxAck {
ctx.delete_multicast_group_queue_item().await?; ctx.delete_multicast_group_queue_item().await?;
} }
} else { } else {
if ctx.is_application_payload() || ctx.is_mac_only_downlink() {
ctx.get_device_data().await?;
if ctx.is_application_payload() { if ctx.is_application_payload() {
ctx.get_device().await?;
ctx.get_device_profile().await?;
ctx.get_application().await?;
ctx.get_tenant().await?;
ctx.get_device_session().await?;
ctx.get_device_queue_item().await?; ctx.get_device_queue_item().await?;
if ctx.is_unconfirmed_downlink() { if ctx.is_unconfirmed_downlink() {
ctx.delete_device_queue_item().await?; ctx.delete_device_queue_item().await?;
@ -116,13 +109,13 @@ impl TxAck {
} }
ctx.increment_a_f_cnt_down()?; ctx.increment_a_f_cnt_down()?;
ctx.save_device_session().await?;
ctx.send_tx_ack_event().await?; ctx.send_tx_ack_event().await?;
} }
if ctx.is_mac_only_downlink() { if ctx.is_mac_only_downlink() {
ctx.get_device_session().await?;
ctx.increment_n_f_cnt_down()?; ctx.increment_n_f_cnt_down()?;
}
ctx.save_device_session().await?; ctx.save_device_session().await?;
} }
@ -140,24 +133,22 @@ impl TxAck {
async fn _handle_relayed(&mut self) -> Result<()> { async fn _handle_relayed(&mut self) -> Result<()> {
self.get_phy_payload_relayed()?; self.get_phy_payload_relayed()?;
self.get_device_data().await?; // the device-data of the relay
if self.is_error() { if self.is_error() {
// We log the tx ack error under the relay as this is the device to which the downlink // We log the tx ack error under the relay as this is the device to which the downlink
// is sent. // is sent.
self.get_device().await?;
self.get_device_profile().await?;
self.get_application().await?;
self.get_tenant().await?;
self.log_tx_ack_error().await?; self.log_tx_ack_error().await?;
} else { } else {
// First handle the relay frame-counter increment. // First handle the relay frame-counter increment.
self.get_device_session().await?;
self.increment_a_f_cnt_down()?; self.increment_a_f_cnt_down()?;
self.save_device_session().await?; self.save_device_session().await?;
// Get data of relayed device.
self.get_device_data_relayed().await?;
// Handle end-device frame-counter increment + queue item. // Handle end-device frame-counter increment + queue item.
if self.is_application_payload_relayed() { if self.is_application_payload_relayed() {
self.get_device_session_relayed().await?;
self.get_device_queue_item().await?; self.get_device_queue_item().await?;
if self.is_unconfirmed_downlink_relayed() { if self.is_unconfirmed_downlink_relayed() {
self.delete_device_queue_item().await?; self.delete_device_queue_item().await?;
@ -172,13 +163,9 @@ impl TxAck {
self.save_device_session_relayed().await?; self.save_device_session_relayed().await?;
// Log tx ack event. // Log tx ack event.
self.get_device_relayed().await?; self.get_device_data_relayed().await?;
self.get_device_profile_relayed().await?;
self.get_application_relayed().await?;
self.get_tenant_relayed().await?;
self.send_tx_ack_event_relayed().await?; self.send_tx_ack_event_relayed().await?;
} else if self.is_mac_only_downlink_relayed() { } else if self.is_mac_only_downlink_relayed() {
self.get_device_session_relayed().await?;
self.increment_n_f_cnt_down_relayed()?; self.increment_n_f_cnt_down_relayed()?;
self.save_device_session_relayed().await?; self.save_device_session_relayed().await?;
} }
@ -225,75 +212,29 @@ impl TxAck {
Ok(()) Ok(())
} }
async fn get_device_session(&mut self) -> Result<()> { async fn get_device_data(&mut self) -> Result<()> {
trace!("Getting device-session"); trace!("Getting device data");
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui)?; let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui)?;
self.device_session = Some(device_session::get(&dev_eui).await?); let (dev, app, t, dp) = get_all_device_data(dev_eui).await?;
self.tenant = Some(t);
self.application = Some(app);
self.device_profile = Some(dp);
self.device = Some(dev);
Ok(()) Ok(())
} }
async fn get_device_session_relayed(&mut self) -> Result<()> { async fn get_device_data_relayed(&mut self) -> Result<()> {
trace!("Getting relayed device-session"); trace!("Getting relayed device data");
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui_relayed)?; let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui_relayed)?;
self.device_session_relayed = Some(device_session::get(&dev_eui).await?); let (dev, app, t, dp) = get_all_device_data(dev_eui).await?;
Ok(()) self.tenant_relayed = Some(t);
} self.application_relayed = Some(app);
self.device_profile_relayed = Some(dp);
self.device_relayed = Some(dev);
async fn get_device(&mut self) -> Result<()> {
trace!("Getting device");
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui)?;
self.device = Some(device::get(&dev_eui).await?);
Ok(())
}
async fn get_device_relayed(&mut self) -> Result<()> {
trace!("Getting relayed device");
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui_relayed)?;
self.device_relayed = Some(device::get(&dev_eui).await?);
Ok(())
}
async fn get_device_profile(&mut self) -> Result<()> {
trace!("Getting device-profile");
self.device_profile =
Some(device_profile::get(&self.device.as_ref().unwrap().device_profile_id).await?);
Ok(())
}
async fn get_device_profile_relayed(&mut self) -> Result<()> {
trace!("Getting relayed device-profile");
self.device_profile_relayed = Some(
device_profile::get(&self.device_relayed.as_ref().unwrap().device_profile_id).await?,
);
Ok(())
}
async fn get_application(&mut self) -> Result<()> {
trace!("Getting application");
self.application =
Some(application::get(&self.device.as_ref().unwrap().application_id).await?);
Ok(())
}
async fn get_application_relayed(&mut self) -> Result<()> {
trace!("Getting relayed application");
self.application_relayed =
Some(application::get(&self.device_relayed.as_ref().unwrap().application_id).await?);
Ok(())
}
async fn get_tenant(&mut self) -> Result<()> {
trace!("Getting tenant");
self.tenant = Some(tenant::get(&self.application.as_ref().unwrap().tenant_id).await?);
Ok(())
}
async fn get_tenant_relayed(&mut self) -> Result<()> {
trace!("Getting relayed tenant");
self.tenant_relayed =
Some(tenant::get(&self.application_relayed.as_ref().unwrap().tenant_id).await?);
Ok(()) Ok(())
} }
@ -353,7 +294,8 @@ impl TxAck {
fn set_device_session_conf_f_cnt(&mut self) -> Result<()> { fn set_device_session_conf_f_cnt(&mut self) -> Result<()> {
trace!("Setting device-session conf_f_cnt"); trace!("Setting device-session conf_f_cnt");
let ds = self.device_session.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
let qi = self.device_queue_item.as_ref().unwrap(); let qi = self.device_queue_item.as_ref().unwrap();
ds.conf_f_cnt = match qi.f_cnt_down { ds.conf_f_cnt = match qi.f_cnt_down {
@ -370,7 +312,8 @@ impl TxAck {
fn set_device_session_conf_f_cnt_relayed(&mut self) -> Result<()> { fn set_device_session_conf_f_cnt_relayed(&mut self) -> Result<()> {
trace!("Setting relayed device-session conf_f_cnt"); trace!("Setting relayed device-session conf_f_cnt");
let ds = self.device_session_relayed.as_mut().unwrap(); let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
let qi = self.device_queue_item.as_ref().unwrap(); let qi = self.device_queue_item.as_ref().unwrap();
ds.conf_f_cnt = match qi.f_cnt_down { ds.conf_f_cnt = match qi.f_cnt_down {
@ -387,7 +330,8 @@ impl TxAck {
fn increment_a_f_cnt_down(&mut self) -> Result<()> { fn increment_a_f_cnt_down(&mut self) -> Result<()> {
trace!("Incrementing a_f_cnt_down"); trace!("Incrementing a_f_cnt_down");
let ds = self.device_session.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.set_a_f_cnt_down(self.downlink_frame.as_ref().unwrap().a_f_cnt_down + 1); ds.set_a_f_cnt_down(self.downlink_frame.as_ref().unwrap().a_f_cnt_down + 1);
Ok(()) Ok(())
@ -396,7 +340,8 @@ impl TxAck {
fn increment_a_f_cnt_down_relayed(&mut self) -> Result<()> { fn increment_a_f_cnt_down_relayed(&mut self) -> Result<()> {
trace!("Incrementing relayed a_f_cnt_down"); trace!("Incrementing relayed a_f_cnt_down");
let ds = self.device_session_relayed.as_mut().unwrap(); let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.set_a_f_cnt_down(ds.get_a_f_cnt_down() + 1); ds.set_a_f_cnt_down(ds.get_a_f_cnt_down() + 1);
Ok(()) Ok(())
@ -405,7 +350,8 @@ impl TxAck {
fn increment_n_f_cnt_down(&mut self) -> Result<()> { fn increment_n_f_cnt_down(&mut self) -> Result<()> {
trace!("Incrementing n_f_cnt_down"); trace!("Incrementing n_f_cnt_down");
let ds = self.device_session.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.n_f_cnt_down += 1; ds.n_f_cnt_down += 1;
Ok(()) Ok(())
@ -414,7 +360,8 @@ impl TxAck {
fn increment_n_f_cnt_down_relayed(&mut self) -> Result<()> { fn increment_n_f_cnt_down_relayed(&mut self) -> Result<()> {
trace!("Incrementing relayed n_f_cnt_down"); trace!("Incrementing relayed n_f_cnt_down");
let ds = self.device_session_relayed.as_mut().unwrap(); let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.n_f_cnt_down += 1; ds.n_f_cnt_down += 1;
Ok(()) Ok(())
@ -422,13 +369,35 @@ impl TxAck {
async fn save_device_session(&self) -> Result<()> { async fn save_device_session(&self) -> Result<()> {
trace!("Saving device-session"); trace!("Saving device-session");
device_session::save(self.device_session.as_ref().unwrap()).await?;
let d = self.device.as_ref().unwrap();
device::partial_update(
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
Ok(()) Ok(())
} }
async fn save_device_session_relayed(&self) -> Result<()> { async fn save_device_session_relayed(&self) -> Result<()> {
trace!("Saving relayed device-session"); trace!("Saving relayed device-session");
device_session::save(self.device_session_relayed.as_ref().unwrap()).await?;
let d = self.device_relayed.as_ref().unwrap();
device::partial_update(
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
Ok(()) Ok(())
} }

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal; use chirpstack_api::internal;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
_block: &lrwn::MACCommandSet, _block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending ConfigureFwdLimitReq mac-command")); return Err(anyhow!("Expected pending ConfigureFwdLimitReq mac-command"));
} }
@ -27,7 +29,7 @@ pub fn handle(
ds.relay = Some(internal::Relay::default()); ds.relay = Some(internal::Relay::default());
} }
info!(dev_eui = %dev.dev_eui, "ConfigureFwdLimitReq acknowledged"); info!(dev_eui = %dev_eui, "ConfigureFwdLimitReq acknowledged");
if let Some(relay) = &mut ds.relay { if let Some(relay) = &mut ds.relay {
relay.join_req_limit_reload_rate = req_pl.reload_rate.join_req_reload_rate as u32; relay.join_req_limit_reload_rate = req_pl.reload_rate.join_req_reload_rate as u32;
@ -115,10 +117,12 @@ mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
device_session: Some(tst.device_session.clone()),
..Default::default()
};
let resp = handle( let resp = handle(
&device::Device::default(), &mut dev,
&mut ds,
&tst.configure_fwd_limit_ans, &tst.configure_fwd_limit_ans,
tst.configure_fwd_limit_req.as_ref(), tst.configure_fwd_limit_req.as_ref(),
); );
@ -130,7 +134,12 @@ mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -3,16 +3,17 @@ use std::iter::zip;
use anyhow::Result; use anyhow::Result;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::storage::{device, device_session}; use crate::storage::device;
use chirpstack_api::internal;
use lrwn::EUI64; use lrwn::EUI64;
pub async fn handle( pub async fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending CtrlUplinkListReq mac-command")); return Err(anyhow!("Expected pending CtrlUplinkListReq mac-command"));
} }
@ -49,7 +50,7 @@ pub async fn handle(
if ans_pl.uplink_list_idx_ack { if ans_pl.uplink_list_idx_ack {
if let Some(relay) = &mut ds.relay { if let Some(relay) = &mut ds.relay {
info!( info!(
dev_eui = %dev.dev_eui, dev_eui = %dev_eui,
uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx, uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx,
ctrl_uplink_action = action, ctrl_uplink_action = action,
w_f_cnt = ans_pl.w_fcnt, w_f_cnt = ans_pl.w_fcnt,
@ -59,12 +60,20 @@ pub async fn handle(
if action == 0 { if action == 0 {
for rd in &relay.devices { for rd in &relay.devices {
if req_pl.ctrl_uplink_action.uplink_list_idx as u32 == rd.index { if req_pl.ctrl_uplink_action.uplink_list_idx as u32 == rd.index {
let mut ds = let dev_eui = EUI64::from_slice(&rd.dev_eui)?;
device_session::get(&EUI64::from_slice(&rd.dev_eui)?).await?; let mut d = device::get(&dev_eui).await?;
let ds = d.get_device_session_mut()?;
if let Some(relay) = &mut ds.relay { if let Some(relay) = &mut ds.relay {
relay.w_f_cnt = ans_pl.w_fcnt; relay.w_f_cnt = ans_pl.w_fcnt;
}; };
device_session::save(&ds).await?; device::partial_update(
dev_eui,
&device::DeviceChangeset {
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
} }
} }
} else if action == 1 { } else if action == 1 {
@ -75,7 +84,7 @@ pub async fn handle(
} }
} else { } else {
warn!( warn!(
dev_eui = %dev.dev_eui, dev_eui = %dev_eui,
uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx, uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx,
"CtrlUplinkListReq not acknowledged", "CtrlUplinkListReq not acknowledged",
); );
@ -88,7 +97,9 @@ pub async fn handle(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::storage;
use crate::test; use crate::test;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -104,6 +115,39 @@ mod test {
async fn test_response() { async fn test_response() {
let _handle = test::prepare().await; let _handle = test::prepare().await;
let t = storage::tenant::create(storage::tenant::Tenant {
name: "test-tenant".into(),
..Default::default()
})
.await
.unwrap();
let app = storage::application::create(storage::application::Application {
name: "test-app".into(),
tenant_id: t.id,
..Default::default()
})
.await
.unwrap();
let dp = storage::device_profile::create(storage::device_profile::DeviceProfile {
name: "test-dp".into(),
tenant_id: t.id,
..Default::default()
})
.await
.unwrap();
let dev = storage::device::create(storage::device::Device {
name: "test-dev".into(),
dev_eui: EUI64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]),
application_id: app.id,
device_profile_id: dp.id,
..Default::default()
})
.await
.unwrap();
let tests = vec![ let tests = vec![
Test { Test {
name: "acked, nothing pending".into(), name: "acked, nothing pending".into(),
@ -120,7 +164,6 @@ mod test {
}, },
device_session_ed: internal::DeviceSession { device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
relay: Some(internal::Relay { relay: Some(internal::Relay {
w_f_cnt: 1, w_f_cnt: 1,
..Default::default() ..Default::default()
@ -136,7 +179,6 @@ mod test {
]), ]),
expected_device_session_ed: internal::DeviceSession { expected_device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
relay: Some(internal::Relay { relay: Some(internal::Relay {
w_f_cnt: 1, w_f_cnt: 1,
..Default::default() ..Default::default()
@ -160,7 +202,6 @@ mod test {
}, },
device_session_ed: internal::DeviceSession { device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
relay: Some(internal::Relay { relay: Some(internal::Relay {
w_f_cnt: 1, w_f_cnt: 1,
..Default::default() ..Default::default()
@ -183,7 +224,6 @@ mod test {
]), ]),
expected_device_session_ed: internal::DeviceSession { expected_device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
relay: Some(internal::Relay { relay: Some(internal::Relay {
w_f_cnt: 10, w_f_cnt: 10,
..Default::default() ..Default::default()
@ -207,7 +247,6 @@ mod test {
}, },
device_session_ed: internal::DeviceSession { device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
..Default::default() ..Default::default()
}, },
ctrl_uplink_list_req: Some(lrwn::MACCommandSet::new(vec![ ctrl_uplink_list_req: Some(lrwn::MACCommandSet::new(vec![
@ -226,7 +265,6 @@ mod test {
]), ]),
expected_device_session_ed: internal::DeviceSession { expected_device_session_ed: internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
..Default::default() ..Default::default()
}, },
expected_error: None, expected_error: None,
@ -236,12 +274,23 @@ mod test {
for tst in &tests { for tst in &tests {
println!("> {}", tst.name); println!("> {}", tst.name);
device_session::save(&tst.device_session_ed).await.unwrap(); device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(tst.device_session_ed.clone())),
..Default::default()
},
)
.await
.unwrap();
let mut relay_dev = device::Device {
device_session: Some(tst.device_session.clone()),
..Default::default()
};
let mut ds = tst.device_session.clone();
let resp = handle( let resp = handle(
&device::Device::default(), &mut relay_dev,
&mut ds,
&tst.ctrl_uplink_list_ans, &tst.ctrl_uplink_list_ans,
tst.ctrl_uplink_list_req.as_ref(), tst.ctrl_uplink_list_req.as_ref(),
) )
@ -254,11 +303,9 @@ mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
let ds = let d = device::get(&dev.dev_eui).await.unwrap();
device_session::get(&EUI64::from_slice(&tst.device_session_ed.dev_eui).unwrap()) let ds = d.get_device_session().unwrap();
.await assert_eq!(&tst.expected_device_session_ed, ds);
.unwrap();
assert_eq!(tst.expected_device_session_ed, ds);
} }
} }
} }

View File

@ -23,15 +23,18 @@ pub async fn handle(
if let lrwn::MACCommand::DevStatusAns(pl) = mac { if let lrwn::MACCommand::DevStatusAns(pl) = mac {
info!(dev_eui = %dev.dev_eui, battery = pl.battery, margin = pl.margin, "DevStatusAns received"); info!(dev_eui = %dev.dev_eui, battery = pl.battery, margin = pl.margin, "DevStatusAns received");
device::set_status( device::partial_update(
&dev.dev_eui, dev.dev_eui,
pl.margin as i32, &device::DeviceChangeset {
pl.battery == 0, margin: Some(pl.margin as i32),
if pl.battery > 0 && pl.battery < 255 { external_power_source: Some(pl.battery == 0),
battery_level: Some(if pl.battery > 0 && pl.battery < 255 {
let v: BigDecimal = ((pl.battery as f32) / 254.0 * 100.0).try_into()?; let v: BigDecimal = ((pl.battery as f32) / 254.0 * 100.0).try_into()?;
Some(v.with_scale(2)) Some(v.with_scale(2))
} else { } else {
None None
}),
..Default::default()
}, },
) )
.await?; .await?;

View File

@ -10,11 +10,14 @@ pub async fn handle(
.first() .first()
.ok_or_else(|| anyhow!("Expected DeviceModeInd"))?; .ok_or_else(|| anyhow!("Expected DeviceModeInd"))?;
if let lrwn::MACCommand::DeviceModeInd(pl) = mac { if let lrwn::MACCommand::DeviceModeInd(pl) = mac {
device::set_enabled_class( device::partial_update(
&dev.dev_eui, dev.dev_eui,
match pl.class { &device::DeviceChangeset {
enabled_class: Some(match pl.class {
lrwn::DeviceModeClass::ClassA => DeviceClass::A, lrwn::DeviceModeClass::ClassA => DeviceClass::A,
lrwn::DeviceModeClass::ClassC => DeviceClass::C, lrwn::DeviceModeClass::ClassC => DeviceClass::C,
}),
..Default::default()
}, },
) )
.await?; .await?;

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal; use chirpstack_api::internal;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending EndDeviceConfReq mac-command")); return Err(anyhow!("Expected pending EndDeviceConfReq mac-command"));
} }
@ -41,7 +43,7 @@ pub fn handle(
&& ans_pl.second_ch_idx_ack && ans_pl.second_ch_idx_ack
&& ans_pl.backoff_ack && ans_pl.backoff_ack
{ {
info!(dev_eui = %dev.dev_eui, "EndDeviceConfReq acknowledged"); info!(dev_eui = %dev_eui, "EndDeviceConfReq acknowledged");
if let Some(relay) = &mut ds.relay { if let Some(relay) = &mut ds.relay {
relay.ed_activation_mode = relay.ed_activation_mode =
@ -57,7 +59,7 @@ pub fn handle(
} }
} else { } else {
warn!( warn!(
dev_eui = %dev.dev_eui, dev_eui = %dev_eui,
second_ch_freq_ack = ans_pl.second_ch_freq_ack, second_ch_freq_ack = ans_pl.second_ch_freq_ack,
second_ch_dr_ack = ans_pl.second_ch_dr_ack, second_ch_dr_ack = ans_pl.second_ch_dr_ack,
second_ch_idx_ack = ans_pl.second_ch_idx_ack, second_ch_idx_ack = ans_pl.second_ch_idx_ack,
@ -175,10 +177,12 @@ mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
device_session: Some(tst.device_session.clone()),
..Default::default()
};
let resp = handle( let resp = handle(
&device::Device::default(), &mut dev,
&mut ds,
&tst.end_device_conf_ans, &tst.end_device_conf_ans,
tst.end_device_conf_req.as_ref(), tst.end_device_conf_req.as_ref(),
); );
@ -190,7 +194,12 @@ mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,14 +2,14 @@ use anyhow::Result;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending FilterListReq mac-command")); return Err(anyhow!("Expected pending FilterListReq mac-command"));
} }
@ -68,6 +68,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -214,13 +215,11 @@ mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device::default(), ..Default::default()
&mut ds, };
&tst.filter_list_ans, let resp = handle(&mut dev, &tst.filter_list_ans, tst.filter_list_req.as_ref());
tst.filter_list_req.as_ref(),
);
if let Some(e) = &tst.expected_error { if let Some(e) = &tst.expected_error {
assert_eq!(true, resp.is_err(), "{}", tst.name); assert_eq!(true, resp.is_err(), "{}", tst.name);
@ -229,7 +228,12 @@ mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -4,15 +4,16 @@ use tracing::{info, warn};
use crate::region; use crate::region;
use crate::storage::device; use crate::storage::device;
use crate::uplink::UplinkFrameSet; use crate::uplink::UplinkFrameSet;
use chirpstack_api::internal;
pub fn handle( pub fn handle(
uplink_frame_set: &UplinkFrameSet, uplink_frame_set: &UplinkFrameSet,
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending LinkADRReq mac-command")); return Err(anyhow!("Expected pending LinkADRReq mac-command"));
} }
@ -82,7 +83,7 @@ pub fn handle(
ds.nb_trans = link_adr_req.redundancy.nb_rep as u32; ds.nb_trans = link_adr_req.redundancy.nb_rep as u32;
ds.enabled_uplink_channel_indices = chans.iter().map(|i| *i as u32).collect::<Vec<u32>>(); ds.enabled_uplink_channel_indices = chans.iter().map(|i| *i as u32).collect::<Vec<u32>>();
info!(dev_eui = %dev.dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged"); info!(dev_eui = %dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged");
} else if !ds.adr && ch_mask_ack { } else if !ds.adr && ch_mask_ack {
// In case the device has ADR disabled, at least it must acknowledge the // In case the device has ADR disabled, at least it must acknowledge the
// channel-mask. It does not have to acknowledge the other parameters. // channel-mask. It does not have to acknowledge the other parameters.
@ -113,7 +114,7 @@ pub fn handle(
ds.tx_power_index = link_adr_req.tx_power as u32; ds.tx_power_index = link_adr_req.tx_power as u32;
} }
info!(dev_eui = %dev.dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged (device has ADR disabled)"); info!(dev_eui = %dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged (device has ADR disabled)");
} else { } else {
// increase the error counter // increase the error counter
let count = ds let count = ds
@ -153,6 +154,7 @@ pub fn handle(
pub mod test { pub mod test {
use super::*; use super::*;
use crate::region; use crate::region;
use chirpstack_api::internal;
use std::collections::HashMap; use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
use uuid::Uuid; use uuid::Uuid;
@ -357,11 +359,11 @@ pub mod test {
}; };
for tst in &tests { for tst in &tests {
let dev = device::Device { let mut dev = device::Device {
dev_eui: lrwn::EUI64::from_str("0102030405060708").unwrap(), dev_eui: lrwn::EUI64::from_str("0102030405060708").unwrap(),
device_session: Some(tst.device_session.clone()),
..Default::default() ..Default::default()
}; };
let mut ds = tst.device_session.clone();
let block = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRAns( let block = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRAns(
tst.link_adr_ans.clone(), tst.link_adr_ans.clone(),
)]); )]);
@ -372,7 +374,7 @@ pub mod test {
None => None, None => None,
}; };
let res = handle(&ufs, &dev, &mut ds, &block, pending.as_ref()); let res = handle(&ufs, &mut dev, &block, pending.as_ref());
if let Some(e) = &tst.expected_error { if let Some(e) = &tst.expected_error {
assert_eq!(true, res.is_err(), "{}", tst.name); assert_eq!(true, res.is_err(), "{}", tst.name);
assert_eq!(e, &format!("{}", res.err().unwrap()), "{}", tst.name); assert_eq!(e, &format!("{}", res.err().unwrap()), "{}", tst.name);
@ -380,7 +382,12 @@ pub mod test {
assert_eq!(true, res.unwrap().is_none(), "{}", tst.name); assert_eq!(true, res.unwrap().is_none(), "{}", tst.name);
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -7,8 +7,6 @@ use crate::config;
use crate::helpers::errors::PrintFullError; use crate::helpers::errors::PrintFullError;
use crate::storage::{application, device, device_profile, mac_command, tenant}; use crate::storage::{application, device, device_profile, mac_command, tenant};
use crate::uplink::UplinkFrameSet; use crate::uplink::UplinkFrameSet;
use chirpstack_api::internal;
use lrwn::EUI64;
pub mod configure_fwd_limit; pub mod configure_fwd_limit;
pub mod ctrl_uplink_list; pub mod ctrl_uplink_list;
@ -41,15 +39,13 @@ pub async fn handle_uplink<'a>(
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
app: &application::Application, app: &application::Application,
dp: &device_profile::DeviceProfile, dp: &device_profile::DeviceProfile,
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
) -> Result<(Vec<lrwn::MACCommandSet>, bool)> { ) -> Result<(Vec<lrwn::MACCommandSet>, bool)> {
let conf = config::get(); let conf = config::get();
if conf.network.mac_commands_disabled { if conf.network.mac_commands_disabled {
return Ok((Vec::new(), false)); return Ok((Vec::new(), false));
} }
let dev_eui = EUI64::from_slice(&ds.dev_eui)?;
let mut cids: Vec<lrwn::CID> = Vec::new(); // to maintain the CID order let mut cids: Vec<lrwn::CID> = Vec::new(); // to maintain the CID order
let mut blocks: HashMap<lrwn::CID, lrwn::MACCommandSet> = HashMap::new(); let mut blocks: HashMap<lrwn::CID, lrwn::MACCommandSet> = HashMap::new();
@ -81,18 +77,18 @@ pub async fn handle_uplink<'a>(
); );
// Get pending mac-command block, this could return None. // Get pending mac-command block, this could return None.
let pending = match mac_command::get_pending(&dev_eui, cid).await { let pending = match mac_command::get_pending(&dev.dev_eui, cid).await {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!(dev_eui = %dev_eui, cid = %cid, error = %e, "Get pending mac-command block error"); error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Get pending mac-command block error");
continue; continue;
} }
}; };
// Delete the pending mac-command. // Delete the pending mac-command.
if pending.is_some() { if pending.is_some() {
if let Err(e) = mac_command::delete_pending(&dev_eui, cid).await { if let Err(e) = mac_command::delete_pending(&dev.dev_eui, cid).await {
error!(dev_eui = %dev_eui, cid = %cid, error = %e, "Delete pending mac-command error"); error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Delete pending mac-command error");
} }
} }
@ -107,13 +103,12 @@ pub async fn handle_uplink<'a>(
app, app,
dp, dp,
dev, dev,
ds,
) )
.await .await
{ {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
warn!(dev_eui = %dev_eui, cid = %cid, error = %e.full(), "Handle mac-command error"); warn!(dev_eui = %dev.dev_eui, cid = %cid, error = %e.full(), "Handle mac-command error");
continue; continue;
} }
}; };
@ -135,8 +130,7 @@ async fn handle(
tenant: &tenant::Tenant, tenant: &tenant::Tenant,
app: &application::Application, app: &application::Application,
dp: &device_profile::DeviceProfile, dp: &device_profile::DeviceProfile,
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
match cid { match cid {
lrwn::CID::DevStatusAns => { lrwn::CID::DevStatusAns => {
@ -144,30 +138,26 @@ async fn handle(
} }
lrwn::CID::DeviceModeInd => device_mode_ind::handle(dev, block).await, lrwn::CID::DeviceModeInd => device_mode_ind::handle(dev, block).await,
lrwn::CID::DeviceTimeReq => device_time::handle(uplink_frame_set, dev, block), lrwn::CID::DeviceTimeReq => device_time::handle(uplink_frame_set, dev, block),
lrwn::CID::LinkADRAns => link_adr::handle(uplink_frame_set, dev, ds, block, pending_block), lrwn::CID::LinkADRAns => link_adr::handle(uplink_frame_set, dev, block, pending_block),
lrwn::CID::LinkCheckReq => link_check::handle(uplink_frame_set, dev, block), lrwn::CID::LinkCheckReq => link_check::handle(uplink_frame_set, dev, block),
lrwn::CID::NewChannelAns => new_channel::handle(dev, ds, block, pending_block), lrwn::CID::NewChannelAns => new_channel::handle(dev, block, pending_block),
lrwn::CID::PingSlotChannelAns => ping_slot_channel::handle(dev, ds, block, pending_block), lrwn::CID::PingSlotChannelAns => ping_slot_channel::handle(dev, block, pending_block),
lrwn::CID::PingSlotInfoReq => ping_slot_info::handle(dev, ds, block), lrwn::CID::PingSlotInfoReq => ping_slot_info::handle(dev, block),
lrwn::CID::RejoinParamSetupAns => rejoin_param_setup::handle(dev, ds, block, pending_block), lrwn::CID::RejoinParamSetupAns => rejoin_param_setup::handle(dev, block, pending_block),
lrwn::CID::RekeyInd => rekey::handle(dev, block), lrwn::CID::RekeyInd => rekey::handle(dev, block),
lrwn::CID::ResetInd => reset::handle(dev, dp, ds, block), lrwn::CID::ResetInd => reset::handle(dev, dp, block),
lrwn::CID::RxParamSetupAns => rx_param_setup::handle(dev, ds, block, pending_block), lrwn::CID::RxParamSetupAns => rx_param_setup::handle(dev, block, pending_block),
lrwn::CID::RxTimingSetupAns => rx_timing_setup::handle(dev, ds, block, pending_block), lrwn::CID::RxTimingSetupAns => rx_timing_setup::handle(dev, block, pending_block),
lrwn::CID::TxParamSetupAns => tx_param_setup::handle(dev, ds, block, pending_block), lrwn::CID::TxParamSetupAns => tx_param_setup::handle(dev, block, pending_block),
lrwn::CID::RelayConfAns => relay_conf::handle(dev, ds, block, pending_block), lrwn::CID::RelayConfAns => relay_conf::handle(dev, block, pending_block),
lrwn::CID::EndDeviceConfAns => end_device_conf::handle(dev, ds, block, pending_block), lrwn::CID::EndDeviceConfAns => end_device_conf::handle(dev, block, pending_block),
lrwn::CID::FilterListAns => filter_list::handle(dev, ds, block, pending_block), lrwn::CID::FilterListAns => filter_list::handle(dev, block, pending_block),
lrwn::CID::UpdateUplinkListAns => update_uplink_list::handle(dev, ds, block, pending_block), lrwn::CID::UpdateUplinkListAns => update_uplink_list::handle(dev, block, pending_block),
lrwn::CID::ConfigureFwdLimitAns => { lrwn::CID::ConfigureFwdLimitAns => configure_fwd_limit::handle(dev, block, pending_block),
configure_fwd_limit::handle(dev, ds, block, pending_block)
}
lrwn::CID::NotifyNewEndDeviceReq => { lrwn::CID::NotifyNewEndDeviceReq => {
notify_new_end_device::handle(tenant, dp, app, dev, block).await notify_new_end_device::handle(tenant, dp, app, dev, block).await
} }
lrwn::CID::CtrlUplinkListAns => { lrwn::CID::CtrlUplinkListAns => ctrl_uplink_list::handle(dev, block, pending_block).await,
ctrl_uplink_list::handle(dev, ds, block, pending_block).await
}
_ => { _ => {
warn!(cid = %cid, "Unexpected CID"); warn!(cid = %cid, "Unexpected CID");
// Return OK, we don't want to break out of the uplink handling. // Return OK, we don't want to break out of the uplink handling.
@ -180,6 +170,8 @@ async fn handle(
pub mod test { pub mod test {
use super::*; use super::*;
use crate::config; use crate::config;
use chirpstack_api::internal;
use lrwn::EUI64;
use uuid::Uuid; use uuid::Uuid;
#[tokio::test] #[tokio::test]
@ -213,16 +205,18 @@ pub mod test {
let t: tenant::Tenant = Default::default(); let t: tenant::Tenant = Default::default();
let app: application::Application = Default::default(); let app: application::Application = Default::default();
let dp: device_profile::DeviceProfile = Default::default(); let dp: device_profile::DeviceProfile = Default::default();
let dev: device::Device = Default::default(); let mut dev = device::Device {
let mut ds = internal::DeviceSession { dev_eui: EUI64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]),
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8], device_session: Some(internal::DeviceSession {
..Default::default()
}),
..Default::default() ..Default::default()
}; };
// must respond // must respond
let cmds = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxTimingSetupAns]); let cmds = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxTimingSetupAns]);
let (resp, must_respond) = handle_uplink(&upfs, &cmds, &t, &app, &dp, &dev, &mut ds) let (resp, must_respond) = handle_uplink(&upfs, &cmds, &t, &app, &dp, &mut dev)
.await .await
.unwrap(); .unwrap();
assert_eq!(0, resp.len()); assert_eq!(0, resp.len());
@ -233,7 +227,7 @@ pub mod test {
conf.network.mac_commands_disabled = true; conf.network.mac_commands_disabled = true;
config::set(conf); config::set(conf);
let (resp, must_respond) = handle_uplink(&upfs, &cmds, &t, &app, &dp, &dev, &mut ds) let (resp, must_respond) = handle_uplink(&upfs, &cmds, &t, &app, &dp, &mut dev)
.await .await
.unwrap(); .unwrap();
assert_eq!(0, resp.len()); assert_eq!(0, resp.len());

View File

@ -62,11 +62,13 @@ pub fn request(
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending NewChannelReq")); return Err(anyhow!("Expected pending NewChannelReq"));
} }
@ -115,7 +117,7 @@ pub fn handle(
.push(req_pl.ch_index as u32); .push(req_pl.ch_index as u32);
} }
info!(dev_eui = %dev.dev_eui, freq = req_pl.freq, channel = req_pl.ch_index, min_dr = req_pl.min_dr, max_dr = req_pl.max_dr, "NewChannelReq acknowledged"); info!(dev_eui = %dev_eui, freq = req_pl.freq, channel = req_pl.ch_index, min_dr = req_pl.min_dr, max_dr = req_pl.max_dr, "NewChannelReq acknowledged");
} else { } else {
let count = ds let count = ds
.mac_command_error_count .mac_command_error_count
@ -124,7 +126,7 @@ pub fn handle(
*count += 1; *count += 1;
warn!( warn!(
dev_eui = %dev.dev_eui, dev_eui = %dev_eui,
freq = req_pl.freq, freq = req_pl.freq,
channel = req_pl.ch_index, channel = req_pl.ch_index,
min_dr = req_pl.min_dr, min_dr = req_pl.min_dr,
@ -469,16 +471,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
device_session: Some(tst.device_session.clone()),
let res = handle(
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds,
&tst.new_channel_ans, let res = handle(&mut dev, &tst.new_channel_ans, tst.new_channel_req.as_ref());
tst.new_channel_req.as_ref(),
);
if let Some(e) = &tst.expected_error { if let Some(e) = &tst.expected_error {
assert_eq!(true, res.is_err(), "{}", tst.name); assert_eq!(true, res.is_err(), "{}", tst.name);
@ -487,7 +485,12 @@ pub mod test {
assert_eq!(true, res.unwrap().is_none(), "{}", tst.name); assert_eq!(true, res.unwrap().is_none(), "{}", tst.name);
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn request(dr: u8, freq: u32) -> lrwn::MACCommandSet { pub fn request(dr: u8, freq: u32) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::PingSlotChannelReq( lrwn::MACCommandSet::new(vec![lrwn::MACCommand::PingSlotChannelReq(
@ -11,11 +10,12 @@ pub fn request(dr: u8, freq: u32) -> lrwn::MACCommandSet {
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Pending PingSlotChannelReq expected")); return Err(anyhow!("Pending PingSlotChannelReq expected"));
} }
@ -66,6 +66,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -181,12 +182,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds, let resp = handle(
&mut dev,
&tst.ping_slot_channel_ans, &tst.ping_slot_channel_ans,
tst.ping_slot_channel_req.as_ref(), tst.ping_slot_channel_req.as_ref(),
); );
@ -198,7 +199,10 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap()
);
} }
} }
} }

View File

@ -2,13 +2,14 @@ use anyhow::Result;
use tracing::info; use tracing::info;
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
let mac = (**block) let mac = (**block)
.first() .first()
.ok_or_else(|| anyhow!("MACCommandSet is empty"))?; .ok_or_else(|| anyhow!("MACCommandSet is empty"))?;
@ -21,7 +22,7 @@ pub fn handle(
ds.class_b_ping_slot_nb = 1 << (7 - pl.periodicity); ds.class_b_ping_slot_nb = 1 << (7 - pl.periodicity);
info!(dev_eui = %dev.dev_eui, periodicity = pl.periodicity, ping_slot_nb = ds.class_b_ping_slot_nb, "PingSlotInfoReq received"); info!(dev_eui = %dev_eui, periodicity = pl.periodicity, ping_slot_nb = ds.class_b_ping_slot_nb, "PingSlotInfoReq received");
Ok(Some(lrwn::MACCommandSet::new(vec![ Ok(Some(lrwn::MACCommandSet::new(vec![
lrwn::MACCommand::PingSlotInfoAns, lrwn::MACCommand::PingSlotInfoAns,
@ -31,22 +32,19 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
#[test] #[test]
fn test_handle() { fn test_handle() {
let mut ds: internal::DeviceSession = Default::default(); let mut dev = device::Device {
device_session: Some(internal::DeviceSession::default()),
..Default::default()
};
let block = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::PingSlotInfoReq( let block = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::PingSlotInfoReq(
lrwn::PingSlotInfoReqPayload { periodicity: 3 }, lrwn::PingSlotInfoReqPayload { periodicity: 3 },
)]); )]);
let res = handle( let res = handle(&mut dev, &block).unwrap();
&device::Device { assert_eq!(16, dev.get_device_session().unwrap().class_b_ping_slot_nb);
..Default::default()
},
&mut ds,
&block,
)
.unwrap();
assert_eq!(16, ds.class_b_ping_slot_nb);
assert_eq!( assert_eq!(
Some(lrwn::MACCommandSet::new(vec![ Some(lrwn::MACCommandSet::new(vec![
lrwn::MACCommand::PingSlotInfoAns, lrwn::MACCommand::PingSlotInfoAns,

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn request(max_time_n: u8, max_count_n: u8) -> lrwn::MACCommandSet { pub fn request(max_time_n: u8, max_count_n: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RejoinParamSetupReq( lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RejoinParamSetupReq(
@ -14,11 +13,12 @@ pub fn request(max_time_n: u8, max_count_n: u8) -> lrwn::MACCommandSet {
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Pending RejoinParamSetupReq expected")); return Err(anyhow!("Pending RejoinParamSetupReq expected"));
} }
@ -57,6 +57,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -159,12 +160,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds, let resp = handle(
&mut dev,
&tst.rejoin_param_setup_ans, &tst.rejoin_param_setup_ans,
tst.rejoin_param_setup_req.as_ref(), tst.rejoin_param_setup_req.as_ref(),
); );
@ -176,7 +177,12 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal; use chirpstack_api::internal;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending RelayConfReq mac-command")); return Err(anyhow!("Expected pending RelayConfReq mac-command"));
} }
@ -43,7 +45,7 @@ pub fn handle(
&& ans_pl.default_ch_idx_ack && ans_pl.default_ch_idx_ack
&& ans_pl.cad_periodicity_ack && ans_pl.cad_periodicity_ack
{ {
info!(dev_eui = %dev.dev_eui, "RelayConfReq acknowledged"); info!(dev_eui = %dev_eui, "RelayConfReq acknowledged");
if let Some(relay) = &mut ds.relay { if let Some(relay) = &mut ds.relay {
relay.enabled = req_pl.channel_settings_relay.start_stop == 1; relay.enabled = req_pl.channel_settings_relay.start_stop == 1;
@ -56,7 +58,7 @@ pub fn handle(
} }
} else { } else {
warn!( warn!(
dev_eui = %dev.dev_eui, dev_eui = %dev_eui,
second_ch_ack_offset_ack = ans_pl.second_ch_ack_offset_ack, second_ch_ack_offset_ack = ans_pl.second_ch_ack_offset_ack,
second_ch_dr_ack = ans_pl.second_ch_dr_ack, second_ch_dr_ack = ans_pl.second_ch_dr_ack,
second_ch_idx_ack = ans_pl.second_ch_idx_ack, second_ch_idx_ack = ans_pl.second_ch_idx_ack,
@ -177,13 +179,11 @@ mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device::default(), ..Default::default()
&mut ds, };
&tst.relay_conf_ans, let resp = handle(&mut dev, &tst.relay_conf_ans, tst.relay_conf_req.as_ref());
tst.relay_conf_req.as_ref(),
);
if let Some(e) = &tst.expected_error { if let Some(e) = &tst.expected_error {
assert_eq!(true, resp.is_err(), "{}", tst.name); assert_eq!(true, resp.is_err(), "{}", tst.name);
@ -192,7 +192,12 @@ mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,16 +2,17 @@ use anyhow::Result;
use tracing::info; use tracing::info;
use crate::storage::{device, device_profile}; use crate::storage::{device, device_profile};
use chirpstack_api::internal;
const SERV_LORAWAN_VERSION: lrwn::Version = lrwn::Version::LoRaWAN1_1; const SERV_LORAWAN_VERSION: lrwn::Version = lrwn::Version::LoRaWAN1_1;
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
dp: &device_profile::DeviceProfile, dp: &device_profile::DeviceProfile,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
let block_mac = (**block) let block_mac = (**block)
.first() .first()
.ok_or_else(|| anyhow!("MACCommandSet is empty"))?; .ok_or_else(|| anyhow!("MACCommandSet is empty"))?;
@ -21,7 +22,7 @@ pub fn handle(
return Err(anyhow!("ResetInd expected")); return Err(anyhow!("ResetInd expected"));
}; };
info!(dev_eui = %dev.dev_eui, dev_lorawan_version = %block_pl.dev_lorawan_version, serv_lorawan_version = %SERV_LORAWAN_VERSION, "ResetInd received"); info!(dev_eui = %dev_eui, dev_lorawan_version = %block_pl.dev_lorawan_version, serv_lorawan_version = %SERV_LORAWAN_VERSION, "ResetInd received");
dp.reset_session_to_boot_params(ds); dp.reset_session_to_boot_params(ds);
@ -41,23 +42,13 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
use std::collections::HashMap; use std::collections::HashMap;
#[test] #[test]
fn test_handle() { fn test_handle() {
let dev: device::Device = Default::default(); let mut dev = device::Device {
let dp = device_profile::DeviceProfile { device_session: Some(internal::DeviceSession {
supports_otaa: false,
abp_rx1_delay: 1,
abp_rx1_dr_offset: 0,
abp_rx2_dr: 0,
abp_rx2_freq: 868300000,
class_b_ping_slot_dr: 2,
class_b_ping_slot_freq: 868100000,
class_b_ping_slot_nb_k: 1,
..Default::default()
};
let mut ds = internal::DeviceSession {
tx_power_index: 3, tx_power_index: 3,
min_supported_tx_power_index: 1, min_supported_tx_power_index: 1,
max_supported_tx_power_index: 5, max_supported_tx_power_index: 5,
@ -71,12 +62,24 @@ pub mod test {
class_b_ping_slot_freq: 868100000, class_b_ping_slot_freq: 868100000,
nb_trans: 3, nb_trans: 3,
..Default::default() ..Default::default()
}),
..Default::default()
};
let dp = device_profile::DeviceProfile {
supports_otaa: false,
abp_rx1_delay: 1,
abp_rx1_dr_offset: 0,
abp_rx2_dr: 0,
abp_rx2_freq: 868300000,
class_b_ping_slot_dr: 2,
class_b_ping_slot_freq: 868100000,
class_b_ping_slot_nb_k: 1,
..Default::default()
}; };
let resp = handle( let resp = handle(
&dev, &mut dev,
&dp, &dp,
&mut ds,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::ResetInd(lrwn::ResetIndPayload { &lrwn::MACCommandSet::new(vec![lrwn::MACCommand::ResetInd(lrwn::ResetIndPayload {
dev_lorawan_version: lrwn::Version::LoRaWAN1_1, dev_lorawan_version: lrwn::Version::LoRaWAN1_1,
})]), })]),
@ -93,7 +96,7 @@ pub mod test {
); );
assert_eq!( assert_eq!(
internal::DeviceSession { &internal::DeviceSession {
rx1_delay: 1, rx1_delay: 1,
rx1_dr_offset: 0, rx1_dr_offset: 0,
rx2_dr: 0, rx2_dr: 0,
@ -110,7 +113,7 @@ pub mod test {
extra_uplink_channels: HashMap::new(), extra_uplink_channels: HashMap::new(),
..Default::default() ..Default::default()
}, },
ds dev.get_device_session().unwrap()
); );
} }
} }

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn request(rx1_dr_offset: u8, rx2_freq: u32, rx2_dr: u8) -> lrwn::MACCommandSet { pub fn request(rx1_dr_offset: u8, rx2_freq: u32, rx2_dr: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxParamSetupReq( lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxParamSetupReq(
@ -18,11 +17,12 @@ pub fn request(rx1_dr_offset: u8, rx2_freq: u32, rx2_dr: u8) -> lrwn::MACCommand
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet, block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending RxParamSetupReq")); return Err(anyhow!("Expected pending RxParamSetupReq"));
} }
@ -70,6 +70,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -182,12 +183,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds, let resp = handle(
&mut dev,
&tst.rx_param_setup_ans, &tst.rx_param_setup_ans,
tst.rx_param_setup_req.as_ref(), tst.rx_param_setup_req.as_ref(),
); );
@ -199,7 +200,12 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::info; use tracing::info;
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn request(rx1_delay: u8) -> lrwn::MACCommandSet { pub fn request(rx1_delay: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxTimingSetupReq( lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxTimingSetupReq(
@ -11,11 +10,13 @@ pub fn request(rx1_delay: u8) -> lrwn::MACCommandSet {
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
_block: &lrwn::MACCommandSet, _block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Pending RxTimingSetupReq expected")); return Err(anyhow!("Pending RxTimingSetupReq expected"));
} }
@ -31,7 +32,7 @@ pub fn handle(
}; };
ds.rx1_delay = req_pl.delay as u32; ds.rx1_delay = req_pl.delay as u32;
info!(dev_eui = %dev.dev_eui, rx1_delay = req_pl.delay, "RxTimingSetupReq acknowledged"); info!(dev_eui = %dev_eui, rx1_delay = req_pl.delay, "RxTimingSetupReq acknowledged");
Ok(None) Ok(None)
} }
@ -39,6 +40,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -100,12 +102,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds, let resp = handle(
&mut dev,
&tst.rx_timing_setup_ans, &tst.rx_timing_setup_ans,
tst.rx_timing_setup_req.as_ref(), tst.rx_timing_setup_req.as_ref(),
); );
@ -117,7 +119,12 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::info; use tracing::info;
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn request( pub fn request(
uplink_dwell_time_400ms: bool, uplink_dwell_time_400ms: bool,
@ -29,11 +28,13 @@ pub fn request(
} }
pub fn handle( pub fn handle(
dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
_block: &lrwn::MACCommandSet, _block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending TxParamSetupReq")); return Err(anyhow!("Expected pending TxParamSetupReq"));
} }
@ -52,13 +53,14 @@ pub fn handle(
ds.downlink_dwell_time_400ms = req_pl.downlink_dwell_time == lrwn::DwellTime::Limit400ms; ds.downlink_dwell_time_400ms = req_pl.downlink_dwell_time == lrwn::DwellTime::Limit400ms;
ds.uplink_max_eirp_index = req_pl.max_eirp as u32; ds.uplink_max_eirp_index = req_pl.max_eirp as u32;
info!(dev_eui = %dev.dev_eui, uplink_dwell_time_400ms = ds.uplink_dwell_time_400ms, downlink_dwell_time_400ms = ds.downlink_dwell_time_400ms, uplink_max_eirp_index = ds.uplink_max_eirp_index, "TxParamSetupReq acknowledged"); info!(dev_eui = %dev_eui, uplink_dwell_time_400ms = ds.uplink_dwell_time_400ms, downlink_dwell_time_400ms = ds.downlink_dwell_time_400ms, uplink_max_eirp_index = ds.uplink_max_eirp_index, "TxParamSetupReq acknowledged");
Ok(None) Ok(None)
} }
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -136,12 +138,12 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds, let resp = handle(
&mut dev,
&tst.tx_param_setup_ans, &tst.tx_param_setup_ans,
tst.tx_param_setup_req.as_ref(), tst.tx_param_setup_req.as_ref(),
); );
@ -153,7 +155,12 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -2,14 +2,14 @@ use anyhow::Result;
use tracing::info; use tracing::info;
use crate::storage::device; use crate::storage::device;
use chirpstack_api::internal;
pub fn handle( pub fn handle(
_dev: &device::Device, dev: &mut device::Device,
ds: &mut internal::DeviceSession,
_block: &lrwn::MACCommandSet, _block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>, pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> { ) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() { if pending.is_none() {
return Err(anyhow!("Expected pending UpdateUplinkListReq mac-command")); return Err(anyhow!("Expected pending UpdateUplinkListReq mac-command"));
} }
@ -43,6 +43,7 @@ pub fn handle(
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use chirpstack_api::internal;
struct Test { struct Test {
name: String, name: String,
@ -124,12 +125,13 @@ pub mod test {
]; ];
for tst in &tests { for tst in &tests {
let mut ds = tst.device_session.clone(); let mut dev = device::Device {
let resp = handle( device_session: Some(tst.device_session.clone()),
&device::Device {
..Default::default() ..Default::default()
}, };
&mut ds,
let resp = handle(
&mut dev,
&tst.update_uplink_list_ans, &tst.update_uplink_list_ans,
tst.update_uplink_list_req.as_ref(), tst.update_uplink_list_req.as_ref(),
); );
@ -141,7 +143,12 @@ pub mod test {
assert_eq!(true, resp.unwrap().is_none()); assert_eq!(true, resp.unwrap().is_none());
} }
assert_eq!(tst.expected_device_session, ds, "{}", tst.name); assert_eq!(
&tst.expected_device_session,
dev.get_device_session().unwrap(),
"{}",
tst.name
);
} }
} }
} }

View File

@ -78,6 +78,9 @@ enum Commands {
#[arg(short, long, value_name = "NAME")] #[arg(short, long, value_name = "NAME")]
name: String, name: String,
}, },
/// Migrate device-sessions from Redis to PostgreSQL.
MigrateDeviceSessionsToPostgres {},
} }
#[tokio::main] #[tokio::main]
@ -116,6 +119,7 @@ async fn main() -> Result<()> {
.unwrap() .unwrap()
} }
Some(Commands::CreateApiKey { name }) => cmd::create_api_key::run(name).await?, Some(Commands::CreateApiKey { name }) => cmd::create_api_key::run(name).await?,
Some(Commands::MigrateDeviceSessionsToPostgres {}) => cmd::migrate_ds_to_pg::run().await?,
None => cmd::root::run().await?, None => cmd::root::run().await?,
} }

View File

@ -10,12 +10,20 @@ use diesel_async::RunQueryDsl;
use tracing::info; use tracing::info;
use uuid::Uuid; use uuid::Uuid;
use chirpstack_api::internal;
use lrwn::{DevAddr, EUI64}; use lrwn::{DevAddr, EUI64};
use super::schema::{application, device, device_profile, multicast_group_device, tenant}; use super::schema::{application, device, device_profile, multicast_group_device, tenant};
use super::{error::Error, fields, get_async_db_conn}; use super::{error::Error, fields, get_async_db_conn};
use crate::api::helpers::FromProto;
use crate::config; use crate::config;
pub enum ValidationStatus {
Ok(u32, Device),
Retransmission(u32, Device),
Reset(u32, Device),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, AsExpression, FromSqlRow)] #[derive(Debug, Clone, Copy, Eq, PartialEq, AsExpression, FromSqlRow)]
#[diesel(sql_type = Text)] #[diesel(sql_type = Text)]
pub enum DeviceClass { pub enum DeviceClass {
@ -95,6 +103,24 @@ pub struct Device {
pub tags: fields::KeyValue, pub tags: fields::KeyValue,
pub variables: fields::KeyValue, pub variables: fields::KeyValue,
pub join_eui: EUI64, pub join_eui: EUI64,
pub secondary_dev_addr: Option<DevAddr>,
pub device_session: Option<internal::DeviceSession>,
}
#[derive(AsChangeset, Debug, Clone, Default)]
#[diesel(table_name = device)]
pub struct DeviceChangeset {
pub last_seen_at: Option<Option<DateTime<Utc>>>,
pub dr: Option<Option<i16>>,
pub dev_addr: Option<Option<DevAddr>>,
pub enabled_class: Option<DeviceClass>,
pub join_eui: Option<EUI64>,
pub secondary_dev_addr: Option<Option<DevAddr>>,
pub device_session: Option<Option<internal::DeviceSession>>,
pub margin: Option<i32>,
pub external_power_source: Option<bool>,
pub battery_level: Option<Option<BigDecimal>>,
pub scheduler_run_after: Option<Option<DateTime<Utc>>>,
} }
impl Device { impl Device {
@ -104,6 +130,22 @@ impl Device {
} }
Ok(()) Ok(())
} }
pub fn get_device_session(&self) -> Result<&internal::DeviceSession, Error> {
self.device_session
.as_ref()
.ok_or_else(|| Error::NotFound(self.dev_eui.to_string()))
}
pub fn get_device_session_mut(&mut self) -> Result<&mut internal::DeviceSession, Error> {
self.device_session
.as_mut()
.ok_or_else(|| Error::NotFound(self.dev_eui.to_string()))
}
pub fn get_dev_addr(&self) -> Result<DevAddr> {
self.dev_addr.ok_or_else(|| anyhow!("DevAddr is not set"))
}
} }
impl Default for Device { impl Default for Device {
@ -134,6 +176,8 @@ impl Default for Device {
tags: fields::KeyValue::new(HashMap::new()), tags: fields::KeyValue::new(HashMap::new()),
variables: fields::KeyValue::new(HashMap::new()), variables: fields::KeyValue::new(HashMap::new()),
join_eui: EUI64::default(), join_eui: EUI64::default(),
secondary_dev_addr: None,
device_session: None,
} }
} }
} }
@ -237,6 +281,230 @@ pub async fn get(dev_eui: &EUI64) -> Result<Device, Error> {
Ok(d) Ok(d)
} }
// Return the device-session matching the given PhyPayload. This will fetch all device-session
// associated with the used DevAddr and based on f_cont and mic, decides which one to use.
// 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(
relayed: bool,
phy: &mut lrwn::PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<ValidationStatus, Error> {
// Get the dev_addr and original f_cnt.
let (dev_addr, f_cnt_orig) = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
(pl.fhdr.devaddr, pl.fhdr.f_cnt)
} else {
return Err(Error::InvalidPayload("MacPayload".to_string()));
};
let mut c = get_async_db_conn().await?;
c.build_transaction()
.run::<ValidationStatus, Error, _>(|c| {
Box::pin(async move {
let mut devices: Vec<Device> = device::dsl::device
.filter(
device::dsl::dev_addr
.eq(&dev_addr)
.or(device::dsl::secondary_dev_addr.eq(&dev_addr)),
)
.filter(device::dsl::is_disabled.eq(false))
.for_update()
.load(c)
.await?;
if devices.is_empty() {
return Err(Error::NotFound(dev_addr.to_string()));
}
for d in &mut devices {
let mut sessions = vec![];
if let Some(ds) = &d.device_session {
sessions.push(ds.clone());
if let Some(ds) = &ds.pending_rejoin_device_session {
sessions.push(*ds.clone());
}
}
for ds in &mut sessions {
if ds.dev_addr != dev_addr.to_vec() {
continue;
}
// 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 = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Check both the full frame-counter and the received frame-counter
// truncated to the 16LSB.
// The latter is needed in case of a frame-counter reset as the
// GetFullFCntUp will think the 16LSB has rolled over and will
// increment the 16MSB bit.
let mut mic_ok = false;
for f_cnt in [full_f_cnt, f_cnt_orig] {
// Set the full f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt;
}
mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok {
break;
}
}
if mic_ok {
let full_f_cnt = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
pl.fhdr.f_cnt
} else {
0
};
if let Some(relay) = &ds.relay {
if !relayed && relay.ed_relay_only {
info!(
dev_eui = %d.dev_eui,
"Only communication through relay is allowed"
);
return Err(Error::NotFound(dev_addr.to_string()));
}
}
if full_f_cnt >= ds.f_cnt_up {
// We immediately save the device-session to make sure that concurrent calls for
// the same uplink will fail on the frame-counter validation.
let ds_f_cnt_up = ds.f_cnt_up;
ds.f_cnt_up = full_f_cnt + 1;
let _ = diesel::update(device::dsl::device.find(d.dev_eui))
.set(device::device_session.eq(&ds.clone()))
.execute(c)
.await?;
// We do return the device-session with original frame-counter
ds.f_cnt_up = ds_f_cnt_up;
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Ok(full_f_cnt, d.clone()));
} else if ds.skip_f_cnt_check {
// re-transmission or frame-counter reset
ds.f_cnt_up = 0;
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Ok(full_f_cnt, d.clone()));
} else if full_f_cnt == (ds.f_cnt_up - 1) {
// re-transmission, the frame-counter did not increment
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Retransmission(full_f_cnt, d.clone()));
} else {
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Reset(full_f_cnt, d.clone()));
}
}
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
}
}
Err(Error::InvalidMIC)
})
})
.await
}
pub async fn get_for_phypayload(
phy: &mut lrwn::PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<Device, Error> {
// Get the dev_addr and original f_cnt.
let (dev_addr, f_cnt_orig) = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
(pl.fhdr.devaddr, pl.fhdr.f_cnt)
} else {
return Err(Error::InvalidPayload("MacPayload".to_string()));
};
let devices: Vec<Device> = device::dsl::device
.filter(
device::dsl::dev_addr
.eq(&dev_addr)
.or(device::dsl::secondary_dev_addr.eq(&dev_addr)),
)
.filter(device::dsl::is_disabled.eq(false))
.load(&mut get_async_db_conn().await?)
.await?;
if devices.is_empty() {
return Err(Error::NotFound(dev_addr.to_string()));
}
for d in &devices {
let mut sessions = vec![];
if let Some(ds) = &d.device_session {
sessions.push(ds.clone());
if let Some(ds) = &ds.pending_rejoin_device_session {
sessions.push(*ds.clone());
}
}
for ds in &mut sessions {
if ds.dev_addr != dev_addr.to_vec() {
continue;
}
// 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 = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Set the full f_cnt
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = full_f_cnt;
}
let mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok && full_f_cnt >= ds.f_cnt_up {
return Ok(d.clone());
}
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
}
}
Err(Error::InvalidMIC)
}
pub async fn update(d: Device) -> Result<Device, Error> { pub async fn update(d: Device) -> Result<Device, Error> {
d.validate()?; d.validate()?;
@ -260,80 +528,14 @@ pub async fn update(d: Device) -> Result<Device, Error> {
Ok(d) Ok(d)
} }
pub async fn set_enabled_class(dev_eui: &EUI64, mode: DeviceClass) -> Result<Device, Error> { pub async fn partial_update(dev_eui: EUI64, d: &DeviceChangeset) -> Result<Device, Error> {
let d: Device = diesel::update(device::dsl::device.find(&dev_eui)) let d = diesel::update(device::dsl::device.find(&dev_eui))
.set(device::enabled_class.eq(&mode)) .set(d)
.get_result(&mut get_async_db_conn().await?) .get_result::<Device>(&mut get_async_db_conn().await?)
.await .await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?; .map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
info!(dev_eui = %dev_eui, enabled_class = %mode, "Enabled class updated");
Ok(d)
}
pub async fn set_join_eui(dev_eui: EUI64, join_eui: EUI64) -> Result<Device, Error> { info!(dev_eui = %dev_eui, "Device partially updated");
let d: Device = diesel::update(device::dsl::device.find(&dev_eui))
.set(device::join_eui.eq(&join_eui))
.get_result(&mut get_async_db_conn().await?)
.await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
info!(dev_eui = %dev_eui, join_eui = %join_eui, "Updated JoinEUI");
Ok(d)
}
pub async fn set_dev_addr(dev_eui: EUI64, dev_addr: DevAddr) -> Result<Device, Error> {
let d: Device = diesel::update(device::dsl::device.find(&dev_eui))
.set(device::dev_addr.eq(&dev_addr))
.get_result(&mut get_async_db_conn().await?)
.await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
info!(dev_eui = %dev_eui, dev_addr = %dev_addr, "Updated DevAddr");
Ok(d)
}
// In case the current_ts has been updated during the last device get and calling this update
// function, this will return a NotFound error. The purpose of this error is to catch concurrent
// scheduling, e.g. Class-A downlink and Class-B/C downlink. In such case we want to terminate one
// of the downlinks.
pub async fn set_scheduler_run_after(
dev_eui: &EUI64,
new_ts: Option<DateTime<Utc>>,
) -> Result<Device, Error> {
diesel::update(device::dsl::device.find(&dev_eui))
.set(device::scheduler_run_after.eq(&new_ts))
.get_result(&mut get_async_db_conn().await?)
.await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))
}
pub async fn set_last_seen_dr(dev_eui: &EUI64, dr: u8) -> Result<Device, Error> {
let d: Device = diesel::update(device::dsl::device.find(&dev_eui))
.set((
device::last_seen_at.eq(Utc::now()),
device::dr.eq(dr as i16),
))
.get_result(&mut get_async_db_conn().await?)
.await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
info!(dev_eui = %dev_eui, dr = dr, "Data-rate updated");
Ok(d)
}
pub async fn set_status(
dev_eui: &EUI64,
margin: i32,
external_power_source: bool,
battery_level: Option<BigDecimal>,
) -> Result<Device, Error> {
let d: Device = diesel::update(device::dsl::device.find(&dev_eui))
.set((
device::margin.eq(Some(margin)),
device::external_power_source.eq(external_power_source),
device::battery_level.eq(battery_level),
))
.get_result(&mut get_async_db_conn().await?)
.await
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
info!(dev_eui = %dev_eui, "Device status updated");
Ok(d) Ok(d)
} }
@ -530,12 +732,36 @@ pub async fn get_with_class_b_c_queue_items(limit: usize) -> Result<Vec<Device>>
.context("Get with Class B/C queue-items transaction") .context("Get with Class B/C queue-items transaction")
} }
// GetFullFCntUp returns the full 32bit frame-counter, given the fCntUp which
// has been truncated to the last 16 LSB.
// Notes:
// * After a succesful validation of the FCntUp and the MIC, don't forget
// to synchronize the device FCntUp with the packet FCnt.
// * In case of a frame-counter rollover, the returned values will be less
// than the given DeviceSession FCntUp. This must be validated outside this
// function!
// * In case of a re-transmission, the returned frame-counter equals
// DeviceSession.FCntUp - 1, as the FCntUp value holds the next expected
// frame-counter, not the FCntUp which was last seen.
fn get_full_f_cnt_up(next_expected_full_fcnt: u32, truncated_f_cnt: u32) -> u32 {
// Handle re-transmission.
if truncated_f_cnt == (((next_expected_full_fcnt % (1 << 16)) as u16).wrapping_sub(1)) as u32 {
return next_expected_full_fcnt - 1;
}
let gap = ((truncated_f_cnt as u16).wrapping_sub((next_expected_full_fcnt % (1 << 16)) as u16))
as u32;
next_expected_full_fcnt.wrapping_add(gap)
}
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use crate::storage; use crate::storage;
use crate::storage::device_queue; use crate::storage::device_queue;
use crate::test; use crate::test;
use lrwn::AES128Key;
struct FilterTest<'a> { struct FilterTest<'a> {
filters: Filters, filters: Filters,
@ -696,13 +922,37 @@ pub mod test {
assert_eq!(0, res.len()); assert_eq!(0, res.len());
// device in Class-B. // device in Class-B.
let d = set_enabled_class(&d.dev_eui, DeviceClass::B).await.unwrap(); let d = partial_update(
d.dev_eui,
&DeviceChangeset {
enabled_class: Some(DeviceClass::B),
..Default::default()
},
)
.await
.unwrap();
let res = get_with_class_b_c_queue_items(10).await.unwrap(); let res = get_with_class_b_c_queue_items(10).await.unwrap();
let d = set_scheduler_run_after(&d.dev_eui, None).await.unwrap(); let d = partial_update(
d.dev_eui,
&DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await
.unwrap();
assert_eq!(1, res.len()); assert_eq!(1, res.len());
// device in Class-C // device in Class-C
let d = set_enabled_class(&d.dev_eui, DeviceClass::C).await.unwrap(); let d = partial_update(
d.dev_eui,
&DeviceChangeset {
enabled_class: Some(DeviceClass::C),
..Default::default()
},
)
.await
.unwrap();
let res = get_with_class_b_c_queue_items(10).await.unwrap(); let res = get_with_class_b_c_queue_items(10).await.unwrap();
assert_eq!(1, res.len()); assert_eq!(1, res.len());
@ -712,7 +962,15 @@ pub mod test {
assert_eq!(0, res.len()); assert_eq!(0, res.len());
// device in class C / downlink is pending. // device in class C / downlink is pending.
let _ = set_scheduler_run_after(&d.dev_eui, None).await.unwrap(); let _ = partial_update(
d.dev_eui,
&DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await
.unwrap();
qi.is_pending = true; qi.is_pending = true;
qi.timeout_after = Some(Utc::now() + Duration::seconds(10)); qi.timeout_after = Some(Utc::now() + Duration::seconds(10));
qi = device_queue::update_item(qi).await.unwrap(); qi = device_queue::update_item(qi).await.unwrap();
@ -726,4 +984,397 @@ pub mod test {
let res = get_with_class_b_c_queue_items(10).await.unwrap(); let res = get_with_class_b_c_queue_items(10).await.unwrap();
assert_eq!(1, res.len()); assert_eq!(1, res.len());
} }
#[test]
fn test_get_full_f_cnt_up() {
// server, device, expected
let tests = vec![
(1, 1, 1), // frame-counter is as expected
(1 << 16, 0, 1 << 16), // frame-counter is as expected
((1 << 16) + 1, 1, (1 << 16) + 1), // frame-counter is as expected
(0, 1, 1), // one frame packet-loss
((1 << 16) + 1, 2, (1 << 16) + 2), // one frame packet-loss
(2, 1, 1), // re-transmission of previous frame
((1 << 16) + 1, 0, (1 << 16)), // re-transmission of previous frame
((1 << 16), (1 << 16) - 1, (1 << 16) - 1), // re-transmission of previous frame
(u32::MAX, 0, 0), // 32bit frame-counter rollover
];
for (i, tst) in tests.iter().enumerate() {
let out = get_full_f_cnt_up(tst.0, tst.1);
assert_eq!(tst.2, out, "Test: {}, expected: {}, got: {}", i, tst.2, out);
}
}
#[tokio::test]
async fn test_device_session() {
let _guard = test::prepare().await;
let t = storage::tenant::create(storage::tenant::Tenant {
name: "test-tenant".into(),
..Default::default()
})
.await
.unwrap();
let dp = storage::device_profile::create(storage::device_profile::DeviceProfile {
name: "test-dp".into(),
tenant_id: t.id,
..Default::default()
})
.await
.unwrap();
let app = storage::application::create(storage::application::Application {
name: "test-app".into(),
tenant_id: t.id,
..Default::default()
})
.await
.unwrap();
let mut devices = vec![
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0101010101010101".into(),
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
f_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
nwk_s_enc_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
f_cnt_up: 100,
skip_f_cnt_check: true,
..Default::default()
}),
..Default::default()
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0202020202020202".into(),
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
f_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
nwk_s_enc_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
f_cnt_up: 200,
..Default::default()
}),
..Default::default()
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0303030303030303".into(),
dev_eui: EUI64::from_be_bytes([3, 3, 3, 3, 3, 3, 3, 3]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
secondary_dev_addr: Some(DevAddr::from_be_bytes([4, 3, 2, 1])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
f_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
nwk_s_enc_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
f_cnt_up: 300,
pending_rejoin_device_session: Some(Box::new(internal::DeviceSession {
dev_addr: vec![0x04, 0x03, 0x02, 0x01],
s_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
nwk_s_enc_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_cnt_up: 0,
..Default::default()
})),
..Default::default()
}),
..Default::default()
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0505050505050505".into(),
dev_eui: EUI64::from_be_bytes([5, 5, 5, 5, 5, 5, 5, 5]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
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()
}),
..Default::default()
},
];
for d in &mut devices {
*d = create(d.clone()).await.unwrap();
}
#[derive(Default)]
struct Test {
name: String,
dev_addr: DevAddr,
s_nwk_s_int_key: AES128Key,
f_nwk_s_int_key: AES128Key,
f_cnt: u32,
expected_retransmission: bool,
expected_reset: bool,
expected_dev_eui: EUI64,
expected_fcnt_up: u32,
expected_error: Option<String>,
}
let tests = vec![
Test {
name: "matching dev_eui 0101010101010101".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[0].get_device_session().unwrap().f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: devices[0].get_device_session().unwrap().f_cnt_up,
expected_dev_eui: devices[0].dev_eui,
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[1].get_device_session().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[1].get_device_session().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[1].get_device_session().unwrap().f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: devices[1].get_device_session().unwrap().f_cnt_up,
expected_dev_eui: devices[1].dev_eui,
expected_error: None,
},
Test {
name: "matching dev_eui 0101010101010101 with frame-counter reset".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: 0,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: 0,
expected_dev_eui: devices[0].dev_eui,
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202 with invalid frame-counter".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[1].get_device_session().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[1].get_device_session().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: 0,
expected_reset: true,
expected_dev_eui: devices[1].dev_eui,
..Default::default()
},
Test {
name: "invalid DevAddr".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x01, 0x01, 0x01]),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].get_device_session().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[0].get_device_session().unwrap().f_cnt_up,
expected_error: Some("Object does not exist (id: 01010101)".to_string()),
..Default::default()
},
Test {
name: "invalid nwk_s_key".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_bytes([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]),
s_nwk_s_int_key: AES128Key::from_bytes([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]),
f_cnt: devices[0].get_device_session().unwrap().f_cnt_up,
expected_error: Some("Invalid MIC".to_string()),
..Default::default()
},
Test {
name: "matching pending rejoin device-session".to_string(),
dev_addr: DevAddr::from_be_bytes([0x04, 0x03, 0x02, 0x01]),
f_nwk_s_int_key: AES128Key::from_bytes([
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04,
]),
s_nwk_s_int_key: AES128Key::from_bytes([
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04,
]),
f_cnt: 0,
expected_dev_eui: devices[2].dev_eui,
expected_fcnt_up: 0,
expected_retransmission: false,
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: devices[3].dev_eui,
expected_fcnt_up: (1 << 16) + 11,
expected_retransmission: false,
expected_error: None,
expected_reset: false,
},
];
for tst in &tests {
println!("> {}", tst.name);
let mut phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
fhdr: lrwn::FHDR {
devaddr: tst.dev_addr,
f_ctrl: lrwn::FCtrl::default(),
f_cnt: tst.f_cnt,
..Default::default()
},
..Default::default()
}),
mic: None,
};
phy.set_uplink_data_mic(
lrwn::MACVersion::LoRaWAN1_0,
0,
0,
0,
&tst.f_nwk_s_int_key,
&tst.s_nwk_s_int_key,
)
.unwrap();
// 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 d = get_for_phypayload_and_incr_f_cnt_up(false, &mut phy, 0, 0).await;
if tst.expected_error.is_some() {
assert_eq!(true, d.is_err());
assert_eq!(
tst.expected_error.as_ref().unwrap(),
&d.err().unwrap().to_string()
);
if let lrwn::Payload::MACPayload(pl) = &phy.payload {
assert_eq!(tst.f_cnt, pl.fhdr.f_cnt);
}
} else {
let d = d.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, d) = d {
assert_eq!(false, tst.expected_retransmission);
assert_eq!(tst.expected_dev_eui, d.dev_eui,);
assert_eq!(tst.expected_fcnt_up, full_f_cnt);
} else if let ValidationStatus::Retransmission(full_f_cnt, d) = d {
assert_eq!(true, tst.expected_retransmission);
assert_eq!(tst.expected_dev_eui, d.dev_eui,);
assert_eq!(tst.expected_fcnt_up, full_f_cnt);
} else if let ValidationStatus::Reset(_, d) = d {
assert_eq!(true, tst.expected_reset);
assert_eq!(tst.expected_dev_eui, d.dev_eui,);
}
}
}
}
} }

View File

@ -1,80 +1,14 @@
use std::collections::HashSet;
use std::io::Cursor; use std::io::Cursor;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use prost::Message; use prost::Message;
use tracing::{error, info, trace};
use super::error::Error; use super::error::Error;
use super::{get_async_redis_conn, redis_key}; use super::{get_async_redis_conn, redis_key};
use crate::api::helpers::FromProto;
use crate::config;
use crate::helpers::errors::PrintFullError;
use chirpstack_api::internal; use chirpstack_api::internal;
use lrwn::{AES128Key, DevAddr, Payload, PhyPayload, EUI64}; use lrwn::EUI64;
pub enum ValidationStatus { pub async fn get(dev_eui: &EUI64) -> Result<internal::DeviceSession, Error> {
Ok(u32, internal::DeviceSession),
Retransmission(u32, internal::DeviceSession),
Reset(u32, internal::DeviceSession),
}
pub async fn save(ds: &internal::DeviceSession) -> Result<()> {
let eui = EUI64::from_slice(&ds.dev_eui)?;
let addr = DevAddr::from_slice(&ds.dev_addr)?;
let conf = config::get();
let addr_key = redis_key(format!("devaddr:{{{}}}", addr));
let ds_key = redis_key(format!("device:{{{}}}:ds", eui));
let b = ds.encode_to_vec();
let ttl = conf.network.device_session_ttl.as_millis() as usize;
// Atomic add and pexpire.
redis::pipe()
.atomic()
.cmd("SADD")
.arg(&addr_key)
.arg(&eui.to_be_bytes())
.ignore()
.cmd("PEXPIRE")
.arg(&addr_key)
.arg(ttl)
.ignore()
.query_async(&mut get_async_redis_conn().await?)
.await?;
// In case there is a pending rejoin session, make sure that the new
// DevAddr also resolves to the device-session.
if let Some(pending_ds) = &ds.pending_rejoin_device_session {
let pending_addr = DevAddr::from_slice(&pending_ds.dev_addr)?;
let pending_addr_key = redis_key(format!("devaddr:{{{}}}", pending_addr));
redis::pipe()
.atomic()
.cmd("SADD")
.arg(&pending_addr_key)
.arg(&eui.to_be_bytes())
.ignore()
.cmd("PEXPIRE")
.arg(&pending_addr_key)
.arg(ttl)
.ignore()
.query_async(&mut get_async_redis_conn().await?)
.await?;
}
redis::cmd("PSETEX")
.arg(ds_key)
.arg(ttl)
.arg(b)
.query_async(&mut get_async_redis_conn().await?)
.await?;
info!(dev_eui = %eui, dev_addr = %addr, "Device-session saved");
Ok(())
}
pub async fn get(dev_eui: &EUI64) -> Result<chirpstack_api::internal::DeviceSession, Error> {
let key = redis_key(format!("device:{{{}}}:ds", dev_eui)); let key = redis_key(format!("device:{{{}}}:ds", dev_eui));
let v: Vec<u8> = redis::cmd("GET") let v: Vec<u8> = redis::cmd("GET")
@ -85,687 +19,7 @@ pub async fn get(dev_eui: &EUI64) -> Result<chirpstack_api::internal::DeviceSess
if v.is_empty() { if v.is_empty() {
return Err(Error::NotFound(dev_eui.to_string())); return Err(Error::NotFound(dev_eui.to_string()));
} }
let ds = chirpstack_api::internal::DeviceSession::decode(&mut Cursor::new(v)) let ds =
.context("Decode device-session")?; internal::DeviceSession::decode(&mut Cursor::new(v)).context("Decode device-session")?;
Ok(ds) Ok(ds)
} }
pub async fn delete(dev_eui: &EUI64) -> Result<()> {
let key = redis_key(format!("device:{{{}}}:ds", dev_eui));
redis::cmd("DEL")
.arg(&key)
.query_async(&mut get_async_redis_conn().await?)
.await?;
info!(dev_eui = %dev_eui, "Device-session deleted");
Ok(())
}
// Return the device-session matching the given PhyPayload. This will fetch all device-session
// associated with the used DevAddr and based on f_cont and mic, decides which one to use.
// 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(
relayed: bool,
phy: &mut PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<ValidationStatus, Error> {
let mut _dev_addr = DevAddr::from_be_bytes([0x00, 0x00, 0x00, 0x00]);
let mut _f_cnt_orig = 0;
// Get the dev_addr and original f_cnt.
if let Payload::MACPayload(pl) = &phy.payload {
_dev_addr = pl.fhdr.devaddr;
_f_cnt_orig = pl.fhdr.f_cnt;
} else {
return Err(Error::InvalidPayload("MacPayload".to_string()));
}
let device_sessions = get_for_dev_addr(_dev_addr)
.await
.context("Get device-sessions for DevAddr")?;
if device_sessions.is_empty() {
return Err(Error::NotFound(_dev_addr.to_string()));
}
for mut ds in device_sessions {
// 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)?;
let s_nwk_s_int_key = AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Check both the full frame-counter and the received frame-counter
// truncated to the 16LSB.
// The latter is needed in case of a frame-counter reset as the
// GetFullFCntUp will think the 16LSB has rolled over and will
// increment the 16MSB bit.
let mut mic_ok = false;
for f_cnt in &[full_f_cnt, _f_cnt_orig] {
// Set the full f_cnt.
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = *f_cnt;
}
mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok {
break;
}
}
if mic_ok {
let full_f_cnt = if let Payload::MACPayload(pl) = &phy.payload {
pl.fhdr.f_cnt
} else {
0
};
if let Some(relay) = &ds.relay {
if !relayed && relay.ed_relay_only {
info!(
dev_eui = hex::encode(ds.dev_eui),
"Only communication through relay is allowed"
);
return Err(Error::NotFound(_dev_addr.to_string()));
}
}
if full_f_cnt >= ds.f_cnt_up {
// Make sure that in case of concurrent calls for the same uplink only one will
// pass. Either the concurrent call would read the incremented uplink frame-counter
// or it is unable to aquire the lock.
let lock_key = redis_key(format!(
"device:{{{}}}:ds:lock:{}",
hex::encode(&ds.dev_eui),
full_f_cnt,
));
let set: bool = redis::cmd("SET")
.arg(&lock_key)
.arg("lock")
.arg("EX")
.arg(1_usize)
.arg("NX")
.query_async(&mut get_async_redis_conn().await?)
.await?;
if !set {
return Ok(ValidationStatus::Retransmission(full_f_cnt, ds));
}
// We immediately save the device-session to make sure that concurrent calls for
// the same uplink will fail on the frame-counter validation.
let ds_f_cnt_up = ds.f_cnt_up;
ds.f_cnt_up = full_f_cnt + 1;
save(&ds).await?;
ds.f_cnt_up = ds_f_cnt_up;
return Ok(ValidationStatus::Ok(full_f_cnt, ds));
} else if ds.skip_f_cnt_check {
// re-transmission or frame-counter reset
ds.f_cnt_up = 0;
return Ok(ValidationStatus::Ok(full_f_cnt, ds));
} else if full_f_cnt == (ds.f_cnt_up - 1) {
// re-transmission, the frame-counter did not increment
return Ok(ValidationStatus::Retransmission(full_f_cnt, ds));
} else {
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)
}
// 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: &mut PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<internal::DeviceSession, Error> {
// 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)
} else {
return Err(Error::InvalidPayload("MacPayload".to_string()));
};
let device_sessions = get_for_dev_addr(dev_addr)
.await
.context("Get device-sessions for DevAddr")?;
if device_sessions.is_empty() {
return Err(Error::NotFound(dev_addr.to_string()));
}
for ds in device_sessions {
// 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)?;
let s_nwk_s_int_key = AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Set the full f_cnt
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = full_f_cnt;
}
let mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
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)
}
async fn get_dev_euis_for_dev_addr(dev_addr: DevAddr) -> Result<Vec<EUI64>> {
let key = redis_key(format!("devaddr:{{{}}}", dev_addr));
let dev_euis: HashSet<Vec<u8>> = redis::cmd("SMEMBERS")
.arg(key)
.query_async(&mut get_async_redis_conn().await?)
.await
.context("Get DevEUIs for DevAddr")?;
let mut out = Vec::new();
for dev_eui in &dev_euis {
out.push(EUI64::from_slice(dev_eui)?);
}
Ok(out)
}
async fn remove_dev_eui_from_dev_addr_set(dev_addr: DevAddr, dev_eui: EUI64) -> Result<()> {
let key = redis_key(format!("devaddr:{{{}}}", dev_addr));
redis::cmd("SREM")
.arg(key)
.arg(&dev_eui.to_be_bytes())
.query_async(&mut get_async_redis_conn().await?)
.await?;
Ok(())
}
async fn get_for_dev_addr(dev_addr: DevAddr) -> Result<Vec<internal::DeviceSession>> {
trace!(dev_addr = %dev_addr, "Getting device-session for DevAddr");
let dev_euis = get_dev_euis_for_dev_addr(dev_addr).await?;
let mut out = Vec::new();
for dev_eui in dev_euis {
let ds = match get(&dev_eui).await {
Ok(v) => v,
Err(e) => {
if let Error::NotFound(_) = e {
if let Err(e) = remove_dev_eui_from_dev_addr_set(dev_addr, dev_eui).await {
error!(dev_addr = %dev_addr, dev_eui = %dev_eui, error = %e.full(), "Remove DevEUI from DevAddr->DevEUI set error");
}
} else {
error!(dev_addr = %dev_addr, dev_eui = %dev_eui, error = %e.full(), "Get device-session for DevEUI error");
}
continue;
}
};
let ds_dev_addr = DevAddr::from_slice(&ds.dev_addr)?;
// When a pending rejoin device-session context is set and it has
// the given devAddr, add it to the items list.
if let Some(pending_ds) = &ds.pending_rejoin_device_session {
let pending_dev_addr = DevAddr::from_slice(&pending_ds.dev_addr)?;
if pending_dev_addr == dev_addr {
out.push(*pending_ds.clone());
}
}
// It is possible that the "main" device-session maps to a different
// devAddr as the PendingRejoinDeviceSession is set (using the devAddr
// that is used for the lookup).
if ds_dev_addr == dev_addr {
out.push(ds);
}
}
Ok(out)
}
// GetFullFCntUp returns the full 32bit frame-counter, given the fCntUp which
// has been truncated to the last 16 LSB.
// Notes:
// * After a succesful validation of the FCntUp and the MIC, don't forget
// to synchronize the device FCntUp with the packet FCnt.
// * In case of a frame-counter rollover, the returned values will be less
// than the given DeviceSession FCntUp. This must be validated outside this
// function!
// * In case of a re-transmission, the returned frame-counter equals
// DeviceSession.FCntUp - 1, as the FCntUp value holds the next expected
// frame-counter, not the FCntUp which was last seen.
fn get_full_f_cnt_up(next_expected_full_fcnt: u32, truncated_f_cnt: u32) -> u32 {
// Handle re-transmission.
if truncated_f_cnt == (((next_expected_full_fcnt % (1 << 16)) as u16).wrapping_sub(1)) as u32 {
return next_expected_full_fcnt - 1;
}
let gap = ((truncated_f_cnt as u16).wrapping_sub((next_expected_full_fcnt % (1 << 16)) as u16))
as u32;
next_expected_full_fcnt.wrapping_add(gap)
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::test;
#[test]
fn test_get_full_f_cnt_up() {
// server, device, expected
let tests = vec![
(1, 1, 1), // frame-counter is as expected
(1 << 16, 0, 1 << 16), // frame-counter is as expected
((1 << 16) + 1, 1, (1 << 16) + 1), // frame-counter is as expected
(0, 1, 1), // one frame packet-loss
((1 << 16) + 1, 2, (1 << 16) + 2), // one frame packet-loss
(2, 1, 1), // re-transmission of previous frame
((1 << 16) + 1, 0, (1 << 16)), // re-transmission of previous frame
((1 << 16), (1 << 16) - 1, (1 << 16) - 1), // re-transmission of previous frame
(u32::MAX, 0, 0), // 32bit frame-counter rollover
];
for (i, tst) in tests.iter().enumerate() {
let out = get_full_f_cnt_up(tst.0, tst.1);
assert_eq!(tst.2, out, "Test: {}, expected: {}, got: {}", i, tst.2, out);
}
}
#[tokio::test]
async fn test_device_session() {
let _guard = test::prepare().await;
let device_sessions = vec![
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01],
s_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
f_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
nwk_s_enc_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
f_cnt_up: 100,
skip_f_cnt_check: true,
..Default::default()
},
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02],
s_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
f_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
nwk_s_enc_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
f_cnt_up: 200,
..Default::default()
},
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03],
s_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
f_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
nwk_s_enc_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
f_cnt_up: 300,
pending_rejoin_device_session: Some(Box::new(internal::DeviceSession {
dev_addr: vec![0x04, 0x03, 0x02, 0x01],
dev_eui: vec![0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03],
s_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
nwk_s_enc_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_cnt_up: 0,
..Default::default()
})),
..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 {
save(ds).await.unwrap();
}
#[derive(Default)]
struct Test {
name: String,
dev_addr: DevAddr,
s_nwk_s_int_key: AES128Key,
f_nwk_s_int_key: AES128Key,
f_cnt: u32,
expected_retransmission: bool,
expected_reset: bool,
expected_dev_eui: EUI64,
expected_fcnt_up: u32,
expected_error: Option<String>,
}
let tests = vec![
Test {
name: "matching dev_eui 0101010101010101".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[0].f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: device_sessions[0].f_cnt_up,
expected_dev_eui: EUI64::from_slice(&device_sessions[0].dev_eui).unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[1].f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: device_sessions[1].f_cnt_up,
expected_dev_eui: EUI64::from_slice(&device_sessions[1].dev_eui).unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0101010101010101 with frame-counter reset".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_cnt: 0,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: 0,
expected_dev_eui: EUI64::from_slice(&device_sessions[0].dev_eui).unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202 with invalid frame-counter".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].s_nwk_s_int_key)
.unwrap(),
f_cnt: 0,
expected_reset: true,
expected_dev_eui: EUI64::from_slice(&device_sessions[1].dev_eui).unwrap(),
..Default::default()
},
Test {
name: "invalid DevAddr".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x01, 0x01, 0x01]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[0].f_cnt_up,
expected_error: Some("Object does not exist (id: 01010101)".to_string()),
..Default::default()
},
Test {
name: "invalid nwk_s_key".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_bytes([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]),
s_nwk_s_int_key: AES128Key::from_bytes([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]),
f_cnt: device_sessions[0].f_cnt_up,
expected_error: Some("Invalid MIC".to_string()),
..Default::default()
},
Test {
name: "matching pending rejoin device-session".to_string(),
dev_addr: DevAddr::from_be_bytes([0x04, 0x03, 0x02, 0x01]),
f_nwk_s_int_key: AES128Key::from_bytes([
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04,
]),
s_nwk_s_int_key: AES128Key::from_bytes([
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04,
]),
f_cnt: 0,
expected_dev_eui: EUI64::from_slice(&device_sessions[2].dev_eui).unwrap(),
expected_fcnt_up: 0,
expected_retransmission: false,
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 {
println!("> {}", tst.name);
let mut phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
fhdr: lrwn::FHDR {
devaddr: tst.dev_addr,
f_ctrl: lrwn::FCtrl::default(),
f_cnt: tst.f_cnt,
..Default::default()
},
..Default::default()
}),
mic: None,
};
phy.set_uplink_data_mic(
lrwn::MACVersion::LoRaWAN1_0,
0,
0,
0,
&tst.f_nwk_s_int_key,
&tst.s_nwk_s_int_key,
)
.unwrap();
// 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(false, &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!(
tst.expected_dev_eui,
EUI64::from_slice(&ds.dev_eui).unwrap()
);
assert_eq!(tst.expected_fcnt_up, full_f_cnt);
} else if let ValidationStatus::Retransmission(full_f_cnt, ds) = ds {
assert_eq!(true, tst.expected_retransmission);
assert_eq!(
tst.expected_dev_eui,
EUI64::from_slice(&ds.dev_eui).unwrap()
);
assert_eq!(tst.expected_fcnt_up, full_f_cnt);
} else if let ValidationStatus::Reset(_, ds) = ds {
assert_eq!(true, tst.expected_reset);
assert_eq!(
tst.expected_dev_eui,
EUI64::from_slice(&ds.dev_eui).unwrap()
);
}
}
}
}
#[tokio::test]
async fn test_get_for_dev_addr() {
let _guard = test::prepare().await;
let dev_eui_1 = EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]);
let dev_eui_2 = EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]);
let dev_addr = DevAddr::from_be_bytes([1, 2, 3, 4]);
let ds_1 = internal::DeviceSession {
dev_addr: dev_addr.to_vec(),
dev_eui: dev_eui_1.to_vec(),
..Default::default()
};
let ds_2 = internal::DeviceSession {
dev_addr: dev_addr.to_vec(),
dev_eui: dev_eui_2.to_vec(),
..Default::default()
};
save(&ds_1).await.unwrap();
save(&ds_2).await.unwrap();
let dss = get_for_dev_addr(dev_addr).await.unwrap();
assert_eq!(2, dss.len());
let dev_euis = get_dev_euis_for_dev_addr(dev_addr).await.unwrap();
assert_eq!(2, dev_euis.len());
// At this point there is still a 'dangling' pointer from DevAddr->DevEUI.
delete(&dev_eui_2).await.unwrap();
let dev_euis = get_dev_euis_for_dev_addr(dev_addr).await.unwrap();
assert_eq!(2, dev_euis.len());
// This should only return one device-session.
let dss = get_for_dev_addr(dev_addr).await.unwrap();
assert_eq!(1, dss.len());
assert_eq!(dev_eui_1.to_vec(), dss[0].dev_eui);
// 'dangling' DevAddr->DevEUI pointers have been cleaned up.
let dev_euis = get_dev_euis_for_dev_addr(dev_addr).await.unwrap();
assert_eq!(1, dev_euis.len());
assert_eq!(dev_eui_1, dev_euis[0]);
}
}

View File

@ -83,18 +83,14 @@ pub async fn save_state(name: &str, state: &str) -> Result<()> {
} }
pub async fn save(name: &str, record: &Record) -> Result<()> { pub async fn save(name: &str, record: &Record) -> Result<()> {
for a in get_aggregations() {
save_for_interval(a, name, record).await?;
}
Ok(())
}
async fn save_for_interval(a: Aggregation, name: &str, record: &Record) -> Result<()> {
if record.metrics.is_empty() { if record.metrics.is_empty() {
return Ok(()); return Ok(());
} }
let mut pipe = redis::pipe();
pipe.atomic();
for a in get_aggregations() {
let ttl = get_ttl(a); let ttl = get_ttl(a);
let ts: DateTime<Local> = match a { let ts: DateTime<Local> = match a {
@ -124,8 +120,6 @@ async fn save_for_interval(a: Aggregation, name: &str, record: &Record) -> Resul
}; };
let key = get_key(&name, a, ts); let key = get_key(&name, a, ts);
let mut pipe = redis::pipe();
pipe.atomic();
for (k, v) in &record.metrics { for (k, v) in &record.metrics {
// Passing a reference to hincr will return a runtime error. // Passing a reference to hincr will return a runtime error.
@ -153,11 +147,13 @@ async fn save_for_interval(a: Aggregation, name: &str, record: &Record) -> Resul
pipe.cmd("PEXPIRE") pipe.cmd("PEXPIRE")
.arg(&key) .arg(&key)
.arg(ttl.as_millis() as usize) .arg(ttl.as_millis() as usize)
.ignore() .ignore();
.query_async(&mut get_async_redis_conn().await?)
.await?;
info!(name = %name, aggregation = %a, "Metrics saved"); info!(name = %name, aggregation = %a, "Metrics saved");
}
pipe.query_async(&mut get_async_redis_conn().await?).await?;
Ok(()) Ok(())
} }
@ -339,9 +335,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::HOUR, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -408,9 +402,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::DAY, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -477,9 +469,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::DAY, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -546,9 +536,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::MONTH, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -607,9 +595,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::HOUR, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -658,9 +644,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::HOUR, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(
@ -709,9 +693,7 @@ pub mod test {
}, },
]; ];
for r in &records { for r in &records {
save_for_interval(Aggregation::HOUR, "test", r) save("test", r).await.unwrap();
.await
.unwrap();
} }
let resp = get( let resp = get(

View File

@ -1,4 +1,5 @@
use std::sync::RwLock; use std::sync::RwLock;
use std::time::Instant;
use anyhow::Result; use anyhow::Result;
use diesel::{ConnectionError, ConnectionResult}; use diesel::{ConnectionError, ConnectionResult};
@ -9,6 +10,7 @@ use diesel_async::AsyncPgConnection;
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use futures_util::future::BoxFuture; use futures_util::future::BoxFuture;
use futures_util::FutureExt; use futures_util::FutureExt;
use prometheus_client::metrics::histogram::{exponential_buckets, Histogram};
use redis::aio::ConnectionLike; use redis::aio::ConnectionLike;
use tokio::sync::RwLock as TokioRwLock; use tokio::sync::RwLock as TokioRwLock;
use tokio::task; use tokio::task;
@ -41,6 +43,7 @@ pub mod tenant;
pub mod user; pub mod user;
use crate::helpers::tls::get_root_certs; use crate::helpers::tls::get_root_certs;
use crate::monitoring::prometheus;
pub type AsyncPgPool = DeadpoolPool<AsyncPgConnection>; pub type AsyncPgPool = DeadpoolPool<AsyncPgConnection>;
pub type AsyncPgPoolConnection = DeadpoolObject<AsyncPgConnection>; pub type AsyncPgPoolConnection = DeadpoolObject<AsyncPgConnection>;
@ -49,6 +52,24 @@ lazy_static! {
static ref ASYNC_PG_POOL: RwLock<Option<AsyncPgPool>> = RwLock::new(None); static ref ASYNC_PG_POOL: RwLock<Option<AsyncPgPool>> = RwLock::new(None);
static ref ASYNC_REDIS_POOL: TokioRwLock<Option<AsyncRedisPool>> = TokioRwLock::new(None); static ref ASYNC_REDIS_POOL: TokioRwLock<Option<AsyncRedisPool>> = TokioRwLock::new(None);
static ref REDIS_PREFIX: RwLock<String> = RwLock::new("".to_string()); static ref REDIS_PREFIX: RwLock<String> = RwLock::new("".to_string());
static ref STORAGE_REDIS_CONN_GET: Histogram = {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_redis_conn_get_duration_seconds",
"Time between requesting a Redis connection and the connection-pool returning it",
histogram.clone(),
);
histogram
};
static ref STORAGE_PG_CONN_GET: Histogram = {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_pg_conn_get_duration_seconds",
"Time between requesting a PostgreSQL connection and the connection-pool returning it",
histogram.clone(),
);
histogram
};
} }
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations"); pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations");
@ -174,7 +195,13 @@ pub fn get_async_db_pool() -> Result<AsyncPgPool> {
pub async fn get_async_db_conn() -> Result<AsyncPgPoolConnection> { pub async fn get_async_db_conn() -> Result<AsyncPgPoolConnection> {
let pool = get_async_db_pool()?; let pool = get_async_db_pool()?;
Ok(pool.get().await?)
let start = Instant::now();
let res = pool.get().await?;
STORAGE_PG_CONN_GET.observe(start.elapsed().as_secs_f64());
Ok(res)
} }
async fn get_async_redis_pool() -> Result<AsyncRedisPool> { async fn get_async_redis_pool() -> Result<AsyncRedisPool> {
@ -189,12 +216,17 @@ async fn get_async_redis_pool() -> Result<AsyncRedisPool> {
pub async fn get_async_redis_conn() -> Result<AsyncRedisPoolConnection> { pub async fn get_async_redis_conn() -> Result<AsyncRedisPoolConnection> {
let pool = get_async_redis_pool().await?; let pool = get_async_redis_pool().await?;
Ok(match pool { let start = Instant::now();
let res = match pool {
AsyncRedisPool::Client(v) => AsyncRedisPoolConnection::Client(v.get().await?), AsyncRedisPool::Client(v) => AsyncRedisPoolConnection::Client(v.get().await?),
AsyncRedisPool::ClusterClient(v) => { AsyncRedisPool::ClusterClient(v) => {
AsyncRedisPoolConnection::ClusterClient(v.clone().get().await?) AsyncRedisPoolConnection::ClusterClient(v.clone().get().await?)
} }
}) };
STORAGE_REDIS_CONN_GET.observe(start.elapsed().as_secs_f64());
Ok(res)
} }
pub fn set_async_db_pool(p: AsyncPgPool) { pub fn set_async_db_pool(p: AsyncPgPool) {

View File

@ -63,6 +63,8 @@ diesel::table! {
tags -> Jsonb, tags -> Jsonb,
variables -> Jsonb, variables -> Jsonb,
join_eui -> Bytea, join_eui -> Bytea,
secondary_dev_addr -> Nullable<Bytea>,
device_session -> Nullable<Bytea>,
} }
} }

View File

@ -12,7 +12,7 @@ use crate::gateway::backend::mock as gateway_mock;
use crate::integration::mock; use crate::integration::mock;
use crate::storage::{ use crate::storage::{
device::{self, DeviceClass}, device::{self, DeviceClass},
device_queue, device_session, downlink_frame, get_async_redis_conn, redis_key, device_queue, downlink_frame, get_async_redis_conn, redis_key,
}; };
use chirpstack_api::{gw, integration as integration_pb, internal, stream}; use chirpstack_api::{gw, integration as integration_pb, internal, stream};
use lrwn::EUI64; use lrwn::EUI64;
@ -27,7 +27,8 @@ pub fn f_cnt_up(dev_eui: EUI64, f_cnt: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(f_cnt, ds.f_cnt_up); assert_eq!(f_cnt, ds.f_cnt_up);
}) })
}) })
@ -37,7 +38,8 @@ pub fn n_f_cnt_down(dev_eui: EUI64, f_cnt: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(f_cnt, ds.n_f_cnt_down); assert_eq!(f_cnt, ds.n_f_cnt_down);
}) })
}) })
@ -47,7 +49,8 @@ pub fn a_f_cnt_down(dev_eui: EUI64, f_cnt: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(f_cnt, ds.a_f_cnt_down); assert_eq!(f_cnt, ds.a_f_cnt_down);
}) })
}) })
@ -57,7 +60,8 @@ pub fn tx_power_index(dev_eui: EUI64, tx_power: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(tx_power, ds.tx_power_index); assert_eq!(tx_power, ds.tx_power_index);
}) })
}) })
@ -67,7 +71,8 @@ pub fn nb_trans(dev_eui: EUI64, nb_trans: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(nb_trans, ds.nb_trans); assert_eq!(nb_trans, ds.nb_trans);
}) })
}) })
@ -78,7 +83,8 @@ pub fn enabled_uplink_channel_indices(dev_eui: EUI64, channels: Vec<u32>) -> Val
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
let channels = channels.clone(); let channels = channels.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(channels, ds.enabled_uplink_channel_indices); assert_eq!(channels, ds.enabled_uplink_channel_indices);
}) })
}) })
@ -88,7 +94,8 @@ pub fn dr(dev_eui: EUI64, dr: u32) -> Validator {
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(dr, ds.dr); assert_eq!(dr, ds.dr);
}) })
}) })
@ -98,7 +105,8 @@ pub fn mac_command_error_count(dev_eui: EUI64, cid: lrwn::CID, count: u32) -> Va
Box::new(move || { Box::new(move || {
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!( assert_eq!(
count, count,
ds.mac_command_error_count ds.mac_command_error_count
@ -115,7 +123,8 @@ pub fn uplink_adr_history(dev_eui: EUI64, uh: Vec<internal::UplinkAdrHistory>) -
let dev_eui = dev_eui.clone(); let dev_eui = dev_eui.clone();
let uh = uh.clone(); let uh = uh.clone();
Box::pin(async move { Box::pin(async move {
let ds = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
let ds = d.get_device_session().unwrap();
assert_eq!(uh, ds.uplink_adr_history); assert_eq!(uh, ds.uplink_adr_history);
}) })
}) })
@ -240,8 +249,9 @@ pub fn device_session(dev_eui: EUI64, ds: internal::DeviceSession) -> Validator
Box::new(move || { Box::new(move || {
let ds = ds.clone(); let ds = ds.clone();
Box::pin(async move { Box::pin(async move {
let ds_get = device_session::get(&dev_eui).await.unwrap(); let d = device::get(&dev_eui).await.unwrap();
assert_eq!(ds, ds_get); let ds_get = d.get_device_session().unwrap();
assert_eq!(&ds, ds_get);
}) })
}) })
} }
@ -249,8 +259,8 @@ pub fn device_session(dev_eui: EUI64, ds: internal::DeviceSession) -> Validator
pub fn no_device_session(dev_eui: EUI64) -> Validator { pub fn no_device_session(dev_eui: EUI64) -> Validator {
Box::new(move || { Box::new(move || {
Box::pin(async move { Box::pin(async move {
let res = device_session::get(&dev_eui).await; let d = device::get(&dev_eui).await.unwrap();
assert_eq!(true, res.is_err()); assert!(d.device_session.is_none());
}) })
}) })
} }

View File

@ -12,7 +12,7 @@ use crate::gateway::backend as gateway_backend;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_profile, device_queue, device_session, gateway, tenant, device_profile, device_queue, gateway, tenant,
}; };
use crate::{config, test, uplink}; use crate::{config, test, uplink};
use chirpstack_api::{common, gw, internal}; use chirpstack_api::{common, gw, internal};
@ -219,33 +219,18 @@ async fn test_sns_uplink() {
.await .await
.unwrap(); .unwrap();
let mut dev_addr = lrwn::DevAddr::from_be_bytes([0, 0, 0, 0]);
dev_addr.set_dev_addr_prefix(lrwn::NetID::from_str("000505").unwrap().dev_addr_prefix());
let dev = device::create(device::Device { let dev = device::create(device::Device {
name: "device".into(), name: "device".into(),
application_id: app.id.clone(), application_id: app.id.clone(),
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::B, enabled_class: DeviceClass::B,
..Default::default() dev_addr: Some(dev_addr),
}) device_session: Some(internal::DeviceSession {
.await
.unwrap();
device_queue::enqueue_item(device_queue::DeviceQueueItem {
dev_eui: dev.dev_eui,
f_port: 10,
data: vec![1, 2, 3, 4],
..Default::default()
})
.await
.unwrap();
let mut dev_addr = lrwn::DevAddr::from_be_bytes([0, 0, 0, 0]);
dev_addr.set_dev_addr_prefix(lrwn::NetID::from_str("000505").unwrap().dev_addr_prefix());
let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: dev_addr.to_vec(), dev_addr: dev_addr.to_vec(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -261,8 +246,22 @@ async fn test_sns_uplink() {
rx2_frequency: 869525000, rx2_frequency: 869525000,
region_config_id: "eu868".into(), region_config_id: "eu868".into(),
..Default::default() ..Default::default()
}; }),
device_session::save(&ds).await.unwrap(); ..Default::default()
})
.await
.unwrap();
let ds = dev.get_device_session().unwrap();
device_queue::enqueue_item(device_queue::DeviceQueueItem {
dev_eui: dev.dev_eui,
f_port: 10,
data: vec![1, 2, 3, 4],
..Default::default()
})
.await
.unwrap();
let mut data_phy = lrwn::PhyPayload { let mut data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR { mhdr: lrwn::MHDR {
@ -346,7 +345,7 @@ async fn test_sns_uplink() {
}, },
phy_payload: hex::decode("600000000a8005000a54972baa8b983cd1").unwrap(), phy_payload: hex::decode("600000000a8005000a54972baa8b983cd1").unwrap(),
dl_meta_data: Some(backend::DLMetaData { dl_meta_data: Some(backend::DLMetaData {
dev_eui: ds.dev_eui.clone(), dev_eui: dev.dev_eui.to_vec(),
dl_freq_1: Some(868.1), dl_freq_1: Some(868.1),
dl_freq_2: Some(869.525), dl_freq_2: Some(869.525),
rx_delay_1: Some(1), rx_delay_1: Some(1),
@ -403,7 +402,7 @@ async fn test_sns_uplink() {
}, },
..Default::default() ..Default::default()
}, },
dev_eui: ds.dev_eui.clone(), dev_eui: dev.dev_eui.to_vec(),
nwk_s_key: Some(backend::KeyEnvelope { nwk_s_key: Some(backend::KeyEnvelope {
kek_label: "".to_string(), kek_label: "".to_string(),
aes_key: ds.nwk_s_enc_key.clone(), aes_key: ds.nwk_s_enc_key.clone(),
@ -466,24 +465,18 @@ async fn test_sns_roaming_not_allowed() {
.await .await
.unwrap(); .unwrap();
let _dev = device::create(device::Device { let mut dev_addr = lrwn::DevAddr::from_be_bytes([0, 0, 0, 0]);
dev_addr.set_dev_addr_prefix(lrwn::NetID::from_str("000505").unwrap().dev_addr_prefix());
let dev = device::create(device::Device {
name: "device".into(), name: "device".into(),
application_id: app.id.clone(), application_id: app.id.clone(),
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::B, enabled_class: DeviceClass::B,
..Default::default() dev_addr: Some(dev_addr),
}) device_session: Some(internal::DeviceSession {
.await
.unwrap();
let mut dev_addr = lrwn::DevAddr::from_be_bytes([0, 0, 0, 0]);
dev_addr.set_dev_addr_prefix(lrwn::NetID::from_str("000505").unwrap().dev_addr_prefix());
let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: dev_addr.to_vec(), dev_addr: dev_addr.to_vec(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -499,8 +492,13 @@ async fn test_sns_roaming_not_allowed() {
rx2_frequency: 869525000, rx2_frequency: 869525000,
region_config_id: "eu868".into(), region_config_id: "eu868".into(),
..Default::default() ..Default::default()
}; }),
device_session::save(&ds).await.unwrap(); ..Default::default()
})
.await
.unwrap();
let ds = dev.get_device_session().unwrap();
let mut data_phy = lrwn::PhyPayload { let mut data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR { mhdr: lrwn::MHDR {

View File

@ -8,16 +8,17 @@ use super::assert;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_profile, device_queue, device_session, gateway, mac_command, reset_redis, tenant, device_profile, device_queue, gateway, mac_command, reset_redis, tenant,
}; };
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink}; use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
use chirpstack_api::{common, gw, integration as integration_pb, internal, stream}; use chirpstack_api::{common, gw, integration as integration_pb, internal, stream};
use lrwn::{AES128Key, EUI64}; use lrwn::{AES128Key, DevAddr, EUI64};
type Function = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>; type Function = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
struct Test { struct Test {
name: String, name: String,
dev_eui: EUI64,
device_queue_items: Vec<device_queue::DeviceQueueItem>, device_queue_items: Vec<device_queue::DeviceQueueItem>,
before_func: Option<Function>, before_func: Option<Function>,
after_func: Option<Function>, after_func: Option<Function>,
@ -93,11 +94,28 @@ async fn test_gateway_filtering() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::B, enabled_class: DeviceClass::B,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
mac_version: common::MacVersion::Lorawan102.into(),
dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
nwk_s_enc_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
f_cnt_up: 7,
n_f_cnt_down: 5,
enabled_uplink_channel_indices: vec![0, 1, 2],
rx1_delay: 1,
rx2_frequency: 869525000,
region_config_id: "eu868".into(),
..Default::default()
}),
..Default::default() ..Default::default()
}) })
.await .await
.unwrap(); .unwrap();
let ds = dev.get_device_session().unwrap();
let mut rx_info_a = gw::UplinkRxInfo { let mut rx_info_a = gw::UplinkRxInfo {
gateway_id: gw_a.gateway_id.to_string(), gateway_id: gw_a.gateway_id.to_string(),
location: Some(Default::default()), location: Some(Default::default()),
@ -128,26 +146,10 @@ async fn test_gateway_filtering() {
}; };
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
nwk_s_enc_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
f_cnt_up: 7,
n_f_cnt_down: 5,
enabled_uplink_channel_indices: vec![0, 1, 2],
rx1_delay: 1,
rx2_frequency: 869525000,
region_config_id: "eu868".into(),
..Default::default()
};
let tests = vec![ let tests = vec![
Test { Test {
name: "private gateway of same tenant".into(), name: "private gateway of same tenant".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -174,6 +176,7 @@ async fn test_gateway_filtering() {
}, },
Test { Test {
name: "private gateway other tenant".into(), name: "private gateway other tenant".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -196,7 +199,7 @@ async fn test_gateway_filtering() {
}), }),
mic: Some([48, 94, 26, 239]), mic: Some([48, 94, 26, 239]),
}, },
assert: vec![assert::f_cnt_up(dev.dev_eui.clone(), 7)], assert: vec![assert::f_cnt_up(dev.dev_eui, 7)],
}, },
]; ];
@ -257,6 +260,7 @@ async fn test_region_config_id_filtering() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -293,9 +297,7 @@ async fn test_region_config_id_filtering() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -312,6 +314,7 @@ async fn test_region_config_id_filtering() {
let tests = vec![ let tests = vec![
Test { Test {
name: "matching config id".into(), name: "matching config id".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -338,6 +341,7 @@ async fn test_region_config_id_filtering() {
}, },
Test { Test {
name: "non-matching configuration id".into(), name: "non-matching configuration id".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -410,12 +414,13 @@ async fn test_lorawan_10_errors() {
.await .await
.unwrap(); .unwrap();
let _dev = device::create(device::Device { let dev = device::create(device::Device {
name: "device".into(), name: "device".into(),
application_id: app.id.clone(), application_id: app.id.clone(),
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -440,9 +445,7 @@ async fn test_lorawan_10_errors() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -459,6 +462,7 @@ async fn test_lorawan_10_errors() {
let tests = vec![ let tests = vec![
Test { Test {
name: "invalid frame-counter (did not increment)".into(), name: "invalid frame-counter (did not increment)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -491,6 +495,7 @@ async fn test_lorawan_10_errors() {
}, },
Test { Test {
name: "invalid frame-counter (reset)".into(), name: "invalid frame-counter (reset)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -522,6 +527,7 @@ async fn test_lorawan_10_errors() {
}, },
Test { Test {
name: "invalid mic".into(), name: "invalid mic".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -605,12 +611,13 @@ async fn test_lorawan_11_errors() {
.await .await
.unwrap(); .unwrap();
let _dev = device::create(device::Device { let dev = device::create(device::Device {
name: "device".into(), name: "device".into(),
application_id: app.id.clone(), application_id: app.id.clone(),
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -641,9 +648,7 @@ async fn test_lorawan_11_errors() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_dr, 3).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_dr, 3).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -660,6 +665,7 @@ async fn test_lorawan_11_errors() {
let tests = vec![ let tests = vec![
Test { Test {
name: "invalid frequency (MIC)".into(), name: "invalid frequency (MIC)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -686,6 +692,7 @@ async fn test_lorawan_11_errors() {
}, },
Test { Test {
name: "invalid frequency (MIC)".into(), name: "invalid frequency (MIC)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -765,6 +772,7 @@ async fn test_lorawan_10_skip_f_cnt() {
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
skip_fcnt_check: true, skip_fcnt_check: true,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -789,9 +797,7 @@ async fn test_lorawan_10_skip_f_cnt() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -809,6 +815,7 @@ async fn test_lorawan_10_skip_f_cnt() {
let tests = vec![ let tests = vec![
Test { Test {
name: "frame-counter is invalid but not 0".into(), name: "frame-counter is invalid but not 0".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -857,6 +864,7 @@ async fn test_lorawan_10_skip_f_cnt() {
}, },
Test { Test {
name: "frame-counter is invalid and 0".into(), name: "frame-counter is invalid and 0".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -958,6 +966,7 @@ async fn test_lorawan_10_device_disabled() {
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
is_disabled: true, is_disabled: true,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -982,9 +991,7 @@ async fn test_lorawan_10_device_disabled() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -1000,6 +1007,7 @@ async fn test_lorawan_10_device_disabled() {
let tests = vec![Test { let tests = vec![Test {
name: "uplink ignored".into(), name: "uplink ignored".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1081,6 +1089,7 @@ async fn test_lorawan_10_uplink() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -1111,9 +1120,7 @@ async fn test_lorawan_10_uplink() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 10).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 10).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -1134,6 +1141,7 @@ async fn test_lorawan_10_uplink() {
let tests = vec![ let tests = vec![
Test { Test {
name: "unconfirmed uplink with payload".into(), name: "unconfirmed uplink with payload".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1184,6 +1192,7 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "unconfirmed uplink with payload using LR-FHSS dr".into(), name: "unconfirmed uplink with payload using LR-FHSS dr".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
Box::pin(async move { Box::pin(async move {
@ -1255,6 +1264,7 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "unconfirmed uplink with payload + ACK".into(), name: "unconfirmed uplink with payload + ACK".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -1333,6 +1343,7 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "unconfirmed uplink without payload (just FPort)".into(), name: "unconfirmed uplink without payload (just FPort)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1383,6 +1394,7 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "confirmed uplink with payload".into(), name: "confirmed uplink with payload".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1494,6 +1506,7 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "confirmed uplink without payload".into(), name: "confirmed uplink without payload".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1604,11 +1617,18 @@ async fn test_lorawan_10_uplink() {
}, },
Test { Test {
name: "uplink of class-c device updates scheduler_run_after".into(), name: "uplink of class-c device updates scheduler_run_after".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui; let dev_eui = dev.dev_eui;
Box::pin(async move { Box::pin(async move {
device::set_enabled_class(&dev_eui, device::DeviceClass::C) device::partial_update(
dev_eui,
&device::DeviceChangeset {
enabled_class: Some(device::DeviceClass::C),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
}) })
@ -1616,7 +1636,13 @@ async fn test_lorawan_10_uplink() {
after_func: Some(Box::new(move || { after_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui; let dev_eui = dev.dev_eui;
Box::pin(async move { Box::pin(async move {
device::set_enabled_class(&dev_eui, device::DeviceClass::A) device::partial_update(
dev_eui,
&device::DeviceChangeset {
enabled_class: Some(device::DeviceClass::A),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
}) })
@ -1700,6 +1726,7 @@ async fn test_lorawan_10_end_to_end_enc() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -1724,9 +1751,7 @@ async fn test_lorawan_10_end_to_end_enc() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds_sess_key_id = internal::DeviceSession { let ds_sess_key_id = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -1743,9 +1768,7 @@ async fn test_lorawan_10_end_to_end_enc() {
}; };
let ds_app_s_key = internal::DeviceSession { let ds_app_s_key = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -1766,6 +1789,7 @@ async fn test_lorawan_10_end_to_end_enc() {
let tests = vec![ let tests = vec![
Test { Test {
name: "end-to-end encryption with session key id".into(), name: "end-to-end encryption with session key id".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1807,7 +1831,7 @@ async fn test_lorawan_10_end_to_end_enc() {
f_port: 1, f_port: 1,
dr: 0, dr: 0,
data: vec![1, 2, 3, 4], data: vec![1, 2, 3, 4],
join_server_context: Some(integration_pb::JoinServerContext { join_server_context: Some(common::JoinServerContext {
session_key_id: "010203".into(), session_key_id: "010203".into(),
..Default::default() ..Default::default()
}), }),
@ -1816,6 +1840,7 @@ async fn test_lorawan_10_end_to_end_enc() {
}, },
Test { Test {
name: "end-to-end encryption with AppSKey".into(), name: "end-to-end encryption with AppSKey".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -1857,7 +1882,7 @@ async fn test_lorawan_10_end_to_end_enc() {
f_port: 1, f_port: 1,
dr: 0, dr: 0,
data: vec![1, 2, 3, 4], data: vec![1, 2, 3, 4],
join_server_context: Some(integration_pb::JoinServerContext { join_server_context: Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope { app_s_key: Some(common::KeyEnvelope {
kek_label: "kek-label".into(), kek_label: "kek-label".into(),
aes_key: vec![1, 2, 3], aes_key: vec![1, 2, 3],
@ -1869,6 +1894,7 @@ async fn test_lorawan_10_end_to_end_enc() {
}, },
Test { Test {
name: "end-to-end encryption using AppSkey + encrypted downlink".into(), name: "end-to-end encryption using AppSkey + encrypted downlink".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -1919,7 +1945,7 @@ async fn test_lorawan_10_end_to_end_enc() {
f_port: 1, f_port: 1,
dr: 0, dr: 0,
data: vec![1, 2, 3, 4], data: vec![1, 2, 3, 4],
join_server_context: Some(integration_pb::JoinServerContext { join_server_context: Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope { app_s_key: Some(common::KeyEnvelope {
kek_label: "kek-label".into(), kek_label: "kek-label".into(),
aes_key: vec![1, 2, 3], aes_key: vec![1, 2, 3],
@ -2028,6 +2054,7 @@ async fn test_lorawan_11_uplink() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -2058,9 +2085,7 @@ async fn test_lorawan_11_uplink() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan110.into(), mac_version: common::MacVersion::Lorawan110.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -2082,6 +2107,7 @@ async fn test_lorawan_11_uplink() {
let tests = vec![ let tests = vec![
Test { Test {
name: "unconfirmed uplink with payload".into(), name: "unconfirmed uplink with payload".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -2132,6 +2158,7 @@ async fn test_lorawan_11_uplink() {
}, },
Test { Test {
name: "unconfirmed uplink with payload + ACK".into(), name: "unconfirmed uplink with payload + ACK".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -2266,6 +2293,7 @@ async fn test_lorawan_10_rx_delay() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -2296,9 +2324,7 @@ async fn test_lorawan_10_rx_delay() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -2318,6 +2344,7 @@ async fn test_lorawan_10_rx_delay() {
let tests = vec![Test { let tests = vec![Test {
name: "confirmed uplink without payload (rx_delay = 3)".into(), name: "confirmed uplink without payload (rx_delay = 3)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -2479,6 +2506,7 @@ async fn test_lorawan_10_mac_commands() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -2509,9 +2537,7 @@ async fn test_lorawan_10_mac_commands() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -2532,6 +2558,7 @@ async fn test_lorawan_10_mac_commands() {
let tests = vec![ let tests = vec![
Test { Test {
name: "unconfirmed uplink + device-status request downlink (FOpts)".into(), name: "unconfirmed uplink + device-status request downlink (FOpts)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dp_id = dp.id.clone(); let dp_id = dp.id.clone();
@ -2624,6 +2651,7 @@ async fn test_lorawan_10_mac_commands() {
Test { Test {
name: "unconfirmed uplink + device-status request downlink (FOpts) + downlink payload" name: "unconfirmed uplink + device-status request downlink (FOpts) + downlink payload"
.into(), .into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -2721,6 +2749,7 @@ async fn test_lorawan_10_mac_commands() {
}, },
Test { Test {
name: "RxTimingSetupAns is answered with an empty downlink".into(), name: "RxTimingSetupAns is answered with an empty downlink".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -2848,6 +2877,7 @@ async fn test_lorawan_11_mac_commands() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -2872,9 +2902,7 @@ async fn test_lorawan_11_mac_commands() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan110.into(), mac_version: common::MacVersion::Lorawan110.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -2928,6 +2956,7 @@ async fn test_lorawan_11_mac_commands() {
let tests = vec![Test { let tests = vec![Test {
name: "uplink mac-command (encrypted fopts)".into(), name: "uplink mac-command (encrypted fopts)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -3042,6 +3071,7 @@ async fn test_lorawan_10_device_queue() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -3066,9 +3096,7 @@ async fn test_lorawan_10_device_queue() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -3089,6 +3117,7 @@ async fn test_lorawan_10_device_queue() {
let tests = vec![ let tests = vec![
Test { Test {
name: "unconfirmed uplink + one unconfirmed downlink payload in queue".into(), name: "unconfirmed uplink + one unconfirmed downlink payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3166,6 +3195,7 @@ async fn test_lorawan_10_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink + two unconfirmed downlinks payload in queue".into(), name: "unconfirmed uplink + two unconfirmed downlinks payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![ device_queue_items: vec![
device_queue::DeviceQueueItem { device_queue::DeviceQueueItem {
id: Uuid::new_v4(), id: Uuid::new_v4(),
@ -3256,6 +3286,7 @@ async fn test_lorawan_10_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink + one confirmed downlink payload in queue".into(), name: "unconfirmed uplink + one confirmed downlink payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3334,6 +3365,7 @@ async fn test_lorawan_10_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink data + downlink payload which exceeds the max payload size (for dr 0)".into(), name: "unconfirmed uplink data + downlink payload which exceeds the max payload size (for dr 0)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3370,6 +3402,7 @@ async fn test_lorawan_10_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink data + one unconfirmed downlink payload in queue (exactly max size for dr 0) + one mac command".into(), name: "unconfirmed uplink data + one unconfirmed downlink payload in queue (exactly max size for dr 0) + one mac command".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3515,6 +3548,7 @@ async fn test_lorawan_11_device_queue() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -3539,9 +3573,7 @@ async fn test_lorawan_11_device_queue() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan110.into(), mac_version: common::MacVersion::Lorawan110.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -3563,6 +3595,7 @@ async fn test_lorawan_11_device_queue() {
let tests = vec![ let tests = vec![
Test { Test {
name: "unconfirmed uplink + one unconfirmed downlink payload in queue".into(), name: "unconfirmed uplink + one unconfirmed downlink payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3640,6 +3673,7 @@ async fn test_lorawan_11_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink + two unconfirmed downlinks payload in queue".into(), name: "unconfirmed uplink + two unconfirmed downlinks payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![ device_queue_items: vec![
device_queue::DeviceQueueItem { device_queue::DeviceQueueItem {
id: Uuid::new_v4(), id: Uuid::new_v4(),
@ -3730,6 +3764,7 @@ async fn test_lorawan_11_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink + one confirmed downlink payload in queue".into(), name: "unconfirmed uplink + one confirmed downlink payload in queue".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3808,6 +3843,7 @@ async fn test_lorawan_11_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink data + downlink payload which exceeds the max payload size (for dr 0)".into(), name: "unconfirmed uplink data + downlink payload which exceeds the max payload size (for dr 0)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3844,6 +3880,7 @@ async fn test_lorawan_11_device_queue() {
}, },
Test { Test {
name: "unconfirmed uplink data + one unconfirmed downlink payload in queue (exactly max size for dr 0) + one mac command".into(), name: "unconfirmed uplink data + one unconfirmed downlink payload in queue (exactly max size for dr 0) + one mac command".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -3992,6 +4029,7 @@ async fn test_lorawan_10_adr() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -4016,9 +4054,7 @@ async fn test_lorawan_10_adr() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -4057,6 +4093,7 @@ async fn test_lorawan_10_adr() {
let tests = vec![ let tests = vec![
Test { Test {
name: "adr triggered".into(), name: "adr triggered".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4160,6 +4197,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "device has adr disabled".into(), name: "device has adr disabled".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4193,6 +4231,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "acknowledgement of pending adr request".into(), name: "acknowledgement of pending adr request".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
@ -4260,6 +4299,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "negative acknowledgement of pending adr request".into(), name: "negative acknowledgement of pending adr request".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
@ -4327,6 +4367,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "adr ack requested".into(), name: "adr ack requested".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4403,6 +4444,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "channel re-configuration triggered".into(), name: "channel re-configuration triggered".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4502,6 +4544,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "new channel re-configuration ack-ed".into(), name: "new channel re-configuration ack-ed".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
@ -4567,6 +4610,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "new channel re-configuration not ack-ed".into(), name: "new channel re-configuration not ack-ed".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
@ -4634,6 +4678,7 @@ async fn test_lorawan_10_adr() {
}, },
Test { Test {
name: "channel re-configuration and adr triggered".into(), name: "channel re-configuration and adr triggered".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4738,6 +4783,7 @@ async fn test_lorawan_10_adr() {
// adr backoff triggered // adr backoff triggered
Test { Test {
name: "adr backoff triggered".into(), name: "adr backoff triggered".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4835,6 +4881,7 @@ async fn test_lorawan_10_device_status_request() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -4859,9 +4906,7 @@ async fn test_lorawan_10_device_status_request() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -4887,6 +4932,7 @@ async fn test_lorawan_10_device_status_request() {
let tests = vec![ let tests = vec![
Test { Test {
name: "must request device-status".into(), name: "must request device-status".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4963,6 +5009,7 @@ async fn test_lorawan_10_device_status_request() {
}, },
Test { Test {
name: "interval has not yet expired".into(), name: "interval has not yet expired".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -4993,6 +5040,7 @@ async fn test_lorawan_10_device_status_request() {
// reporting device-status // reporting device-status
Test { Test {
name: "reporting device-status".into(), name: "reporting device-status".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
before_func: None, before_func: None,
after_func: None, after_func: None,
@ -5098,6 +5146,7 @@ async fn test_lorawan_11_receive_window_selection() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -5128,9 +5177,7 @@ async fn test_lorawan_11_receive_window_selection() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info_lr_fhss, 8).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan110.into(), mac_version: common::MacVersion::Lorawan110.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -5155,6 +5202,7 @@ async fn test_lorawan_11_receive_window_selection() {
run_test(&Test { run_test(&Test {
name: "unconfirmed uplink with payload (rx1)".into(), name: "unconfirmed uplink with payload (rx1)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -5224,6 +5272,7 @@ async fn test_lorawan_11_receive_window_selection() {
run_test(&Test { run_test(&Test {
name: "unconfirmed uplink with payload (rx2)".into(), name: "unconfirmed uplink with payload (rx2)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -5293,6 +5342,7 @@ async fn test_lorawan_11_receive_window_selection() {
run_test(&Test { run_test(&Test {
name: "unconfirmed uplink with payload (rx1 + rx2)".into(), name: "unconfirmed uplink with payload (rx1 + rx2)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -5391,6 +5441,7 @@ async fn test_lorawan_11_receive_window_selection() {
run_test(&Test { run_test(&Test {
name: "unconfirmed uplink with payload (rx1, payload exceeds rx2 limit)".into(), name: "unconfirmed uplink with payload (rx1, payload exceeds rx2 limit)".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -5497,7 +5548,6 @@ async fn test_lorawan_11_receive_window_selection() {
async fn run_test(t: &Test) { async fn run_test(t: &Test) {
println!("> {}", t.name); println!("> {}", t.name);
reset_redis().await.unwrap(); reset_redis().await.unwrap();
integration::set_mock().await; integration::set_mock().await;
@ -5506,12 +5556,16 @@ async fn run_test(t: &Test) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
if let Some(ds) = &t.device_session { device_queue::flush_for_dev_eui(&t.dev_eui).await.unwrap();
let _ = device_session::save(&ds).await.unwrap(); device::partial_update(
t.dev_eui,
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); &device::DeviceChangeset {
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); device_session: Some(t.device_session.clone()),
} ..Default::default()
},
)
.await
.unwrap();
if let Some(f) = &t.before_func { if let Some(f) = &t.before_func {
f().await; f().await;

View File

@ -5,7 +5,7 @@ use crate::gpstime::ToGpsTime;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_gateway, device_profile, device_queue, device_session, gateway, reset_redis, tenant, device_gateway, device_profile, device_queue, gateway, reset_redis, tenant,
}; };
use crate::{ use crate::{
config, downlink, downlink::classb, gateway::backend as gateway_backend, integration, test, config, downlink, downlink::classb, gateway::backend as gateway_backend, integration, test,
@ -16,6 +16,7 @@ use lrwn::{DevAddr, EUI64};
struct UplinkTest { struct UplinkTest {
name: String, name: String,
dev_eui: EUI64,
device_queue_items: Vec<device_queue::DeviceQueueItem>, device_queue_items: Vec<device_queue::DeviceQueueItem>,
device_session: Option<internal::DeviceSession>, device_session: Option<internal::DeviceSession>,
tx_info: gw::UplinkTxInfo, tx_info: gw::UplinkTxInfo,
@ -26,6 +27,7 @@ struct UplinkTest {
struct DownlinkTest { struct DownlinkTest {
name: String, name: String,
dev_eui: EUI64,
device_queue_items: Vec<device_queue::DeviceQueueItem>, device_queue_items: Vec<device_queue::DeviceQueueItem>,
device_session: Option<internal::DeviceSession>, device_session: Option<internal::DeviceSession>,
device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>, device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>,
@ -80,6 +82,7 @@ async fn test_uplink() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -103,9 +106,7 @@ async fn test_uplink() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 0).unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -130,6 +131,7 @@ async fn test_uplink() {
// trigger beacon locked // trigger beacon locked
run_uplink_test(&UplinkTest { run_uplink_test(&UplinkTest {
name: "trigger beacon locked".into(), name: "trigger beacon locked".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
device_session: Some(ds.clone()), device_session: Some(ds.clone()),
tx_info: tx_info.clone(), tx_info: tx_info.clone(),
@ -164,6 +166,7 @@ async fn test_uplink() {
// trigger beacon unlocked // trigger beacon unlocked
run_uplink_test(&UplinkTest { run_uplink_test(&UplinkTest {
name: "trigger beacon locked".into(), name: "trigger beacon locked".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![], device_queue_items: vec![],
device_session: Some(ds.clone()), device_session: Some(ds.clone()),
tx_info: tx_info.clone(), tx_info: tx_info.clone(),
@ -244,15 +247,14 @@ async fn test_downlink_scheduler() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::B, enabled_class: DeviceClass::B,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
.unwrap(); .unwrap();
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -291,6 +293,7 @@ async fn test_downlink_scheduler() {
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "class-b downlink".into(), name: "class-b downlink".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -342,6 +345,7 @@ async fn test_downlink_scheduler() {
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "scheduler_run_after has not yet expired".into(), name: "scheduler_run_after has not yet expired".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -356,12 +360,19 @@ async fn test_downlink_scheduler() {
.await; .await;
// remove the schedule run after // remove the schedule run after
device::set_scheduler_run_after(&dev.dev_eui.clone(), None) device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "class-b downlink with more data".into(), name: "class-b downlink with more data".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![ device_queue_items: vec![
device_queue::DeviceQueueItem { device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
@ -434,12 +445,16 @@ async fn run_uplink_test(t: &UplinkTest) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
if let Some(ds) = &t.device_session { device_queue::flush_for_dev_eui(&t.dev_eui).await.unwrap();
let _ = device_session::save(&ds).await.unwrap(); device::partial_update(
t.dev_eui,
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); &device::DeviceChangeset {
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); device_session: Some(t.device_session.clone()),
} ..Default::default()
},
)
.await
.unwrap();
for qi in &t.device_queue_items { for qi in &t.device_queue_items {
let _ = device_queue::enqueue_item(qi.clone()).await.unwrap(); let _ = device_queue::enqueue_item(qi.clone()).await.unwrap();
@ -471,13 +486,16 @@ async fn run_scheduler_test(t: &DownlinkTest) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
device_queue::flush_for_dev_eui(&t.dev_eui).await.unwrap();
if let Some(ds) = &t.device_session { device::partial_update(
let _ = device_session::save(&ds).await.unwrap(); t.dev_eui,
&device::DeviceChangeset {
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); device_session: Some(t.device_session.clone()),
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); ..Default::default()
} },
)
.await
.unwrap();
if let Some(rx_info) = &t.device_gateway_rx_info { if let Some(rx_info) = &t.device_gateway_rx_info {
let _ = device_gateway::save_rx_info(rx_info).await.unwrap(); let _ = device_gateway::save_rx_info(rx_info).await.unwrap();

View File

@ -4,14 +4,15 @@ use super::assert;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_gateway, device_profile, device_queue, device_session, gateway, reset_redis, tenant, device_gateway, device_profile, device_queue, gateway, reset_redis, tenant,
}; };
use crate::{downlink, gateway::backend as gateway_backend, integration, test}; use crate::{downlink, gateway::backend as gateway_backend, integration, test};
use chirpstack_api::{common, gw, internal}; use chirpstack_api::{common, gw, internal};
use lrwn::EUI64; use lrwn::{DevAddr, EUI64};
struct DownlinkTest { struct DownlinkTest {
name: String, name: String,
dev_eui: EUI64,
device_queue_items: Vec<device_queue::DeviceQueueItem>, device_queue_items: Vec<device_queue::DeviceQueueItem>,
device_session: Option<internal::DeviceSession>, device_session: Option<internal::DeviceSession>,
device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>, device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>,
@ -71,6 +72,7 @@ async fn test_downlink_scheduler() {
device_profile_id: dp.id.clone(), device_profile_id: dp.id.clone(),
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]), dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
enabled_class: DeviceClass::C, enabled_class: DeviceClass::C,
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
..Default::default() ..Default::default()
}) })
.await .await
@ -86,10 +88,8 @@ async fn test_downlink_scheduler() {
}; };
let ds = internal::DeviceSession { let ds = internal::DeviceSession {
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan104.into(),
join_eui: vec![8, 7, 6, 5, 4, 3, 2, 1],
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
mac_version: common::MacVersion::Lorawan104.into(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
nwk_s_enc_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], nwk_s_enc_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -112,6 +112,7 @@ async fn test_downlink_scheduler() {
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "device has not yet sent an uplink".into(), name: "device has not yet sent an uplink".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -126,12 +127,19 @@ async fn test_downlink_scheduler() {
.await; .await;
// remove the schedule run after // remove the schedule run after
device::set_scheduler_run_after(&dev.dev_eui.clone(), None) device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "unconfirmed data".into(), name: "unconfirmed data".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -178,6 +186,7 @@ async fn test_downlink_scheduler() {
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "scheduler_run_after has not yet expired".into(), name: "scheduler_run_after has not yet expired".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -192,12 +201,19 @@ async fn test_downlink_scheduler() {
.await; .await;
// remove the schedule run after // remove the schedule run after
device::set_scheduler_run_after(&dev.dev_eui.clone(), None) device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "unconfirmed data".into(), name: "unconfirmed data".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -246,12 +262,19 @@ async fn test_downlink_scheduler() {
.await; .await;
// remove the schedule run after // remove the schedule run after
device::set_scheduler_run_after(&dev.dev_eui.clone(), None) device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
scheduler_run_after: Some(None),
..Default::default()
},
)
.await .await
.unwrap(); .unwrap();
run_scheduler_test(&DownlinkTest { run_scheduler_test(&DownlinkTest {
name: "unconfirmed data".into(), name: "unconfirmed data".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![device_queue::DeviceQueueItem { device_queue_items: vec![device_queue::DeviceQueueItem {
id: Uuid::nil(), id: Uuid::nil(),
dev_eui: dev.dev_eui.clone(), dev_eui: dev.dev_eui.clone(),
@ -276,13 +299,16 @@ async fn run_scheduler_test(t: &DownlinkTest) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
device_queue::flush_for_dev_eui(&t.dev_eui).await.unwrap();
if let Some(ds) = &t.device_session { device::partial_update(
let _ = device_session::save(&ds).await.unwrap(); t.dev_eui,
&device::DeviceChangeset {
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); device_session: Some(t.device_session.clone()),
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); ..Default::default()
} },
)
.await
.unwrap();
if let Some(rx_info) = &t.device_gateway_rx_info { if let Some(rx_info) = &t.device_gateway_rx_info {
let _ = device_gateway::save_rx_info(rx_info).await.unwrap(); let _ = device_gateway::save_rx_info(rx_info).await.unwrap();

View File

@ -156,8 +156,6 @@ async fn test_js() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan103.into(), mac_version: common::MacVersion::Lorawan103.into(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
@ -225,8 +223,6 @@ async fn test_js() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan103.into(), mac_version: common::MacVersion::Lorawan103.into(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
@ -255,7 +251,7 @@ async fn test_js() {
..Default::default() ..Default::default()
}), }),
dev_addr: "01020304".into(), dev_addr: "01020304".into(),
join_server_context: Some(integration_pb::JoinServerContext { join_server_context: Some(common::JoinServerContext {
session_key_id: "01020304".into(), session_key_id: "01020304".into(),
..Default::default() ..Default::default()
}), }),
@ -297,8 +293,6 @@ async fn test_js() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan103.into(), mac_version: common::MacVersion::Lorawan103.into(),
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], s_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],
@ -330,7 +324,7 @@ async fn test_js() {
..Default::default() ..Default::default()
}), }),
dev_addr: "01020304".into(), dev_addr: "01020304".into(),
join_server_context: Some(integration_pb::JoinServerContext { join_server_context: Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope { app_s_key: Some(common::KeyEnvelope {
kek_label: "kek-label".into(), kek_label: "kek-label".into(),
aes_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], aes_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8],

View File

@ -8,7 +8,7 @@ use super::assert;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_keys, device_profile, gateway, reset_redis, tenant, device_keys, device_profile, gateway, tenant,
}; };
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink}; use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
use chirpstack_api::{common, gw, internal, stream}; use chirpstack_api::{common, gw, internal, stream};
@ -19,6 +19,7 @@ type Function = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
struct Test { struct Test {
name: String, name: String,
dev_eui: EUI64,
before_func: Option<Function>, before_func: Option<Function>,
after_func: Option<Function>, after_func: Option<Function>,
tx_info: gw::UplinkTxInfo, tx_info: gw::UplinkTxInfo,
@ -153,6 +154,7 @@ async fn test_gateway_filtering() {
let tests = vec![ let tests = vec![
Test { Test {
name: "private gateway of same tenant".into(), name: "private gateway of same tenant".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -168,8 +170,6 @@ async fn test_gateway_filtering() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200, 128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200,
@ -198,6 +198,7 @@ async fn test_gateway_filtering() {
}, },
Test { Test {
name: "private gateway other tenant".into(), name: "private gateway other tenant".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -375,6 +376,7 @@ async fn test_lorawan_10() {
let tests = vec![ let tests = vec![
Test { Test {
name: "dev-nonce already used".into(), name: "dev-nonce already used".into(),
dev_eui: dev.dev_eui,
before_func: None, before_func: None,
after_func: None, after_func: None,
rx_info: rx_info.clone(), rx_info: rx_info.clone(),
@ -387,6 +389,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "join-request accepted".into(), name: "join-request accepted".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -407,8 +410,6 @@ async fn test_lorawan_10() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200, 128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200,
@ -576,6 +577,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "join-request accepted + skip fcnt check".into(), name: "join-request accepted + skip fcnt check".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -602,8 +604,6 @@ async fn test_lorawan_10() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200, 128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200,
@ -633,6 +633,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "join-request accepted + cflist".into(), name: "join-request accepted + cflist".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -649,8 +650,6 @@ async fn test_lorawan_10() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200, 128, 47, 168, 41, 62, 215, 212, 79, 19, 83, 183, 201, 43, 169, 125, 200,
@ -786,6 +785,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "join-request accepted + class-b supported".into(), name: "join-request accepted + class-b supported".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
let dp_id = dp.id.clone(); let dp_id = dp.id.clone();
@ -813,6 +813,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "join-request accepted + class-c supported".into(), name: "join-request accepted + class-c supported".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
let dp_id = dp.id.clone(); let dp_id = dp.id.clone();
@ -840,6 +841,7 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "device disabled".into(), name: "device disabled".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -997,6 +999,7 @@ async fn test_lorawan_11() {
let tests = vec![ let tests = vec![
Test { Test {
name: "dev-nonce already used".into(), name: "dev-nonce already used".into(),
dev_eui: dev.dev_eui,
before_func: None, before_func: None,
after_func: None, after_func: None,
rx_info: rx_info.clone(), rx_info: rx_info.clone(),
@ -1009,6 +1012,7 @@ async fn test_lorawan_11() {
}, },
Test { Test {
name: "join-request accepted".into(), name: "join-request accepted".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
Box::pin(async move { Box::pin(async move {
@ -1025,8 +1029,6 @@ async fn test_lorawan_11() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![2, 2, 3, 4, 5, 6, 7, 8],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan110.into(), mac_version: common::MacVersion::Lorawan110.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
98, 222, 198, 158, 98, 155, 205, 235, 143, 171, 203, 19, 221, 9, 1, 231, 98, 222, 198, 158, 98, 155, 205, 235, 143, 171, 203, 19, 221, 9, 1, 231,
@ -1189,6 +1191,7 @@ async fn test_lorawan_11() {
}, },
Test { Test {
name: "join-request accepted + class-c supported".into(), name: "join-request accepted + class-c supported".into(),
dev_eui: dev.dev_eui,
before_func: Some(Box::new(move || { before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui.clone(); let dev_eui = dev.dev_eui.clone();
let dp_id = dp.id.clone(); let dp_id = dp.id.clone();
@ -1224,8 +1227,6 @@ async fn test_lorawan_11() {
async fn run_test(t: &Test) { async fn run_test(t: &Test) {
println!("> {}", t.name); println!("> {}", t.name);
reset_redis().await.unwrap();
let mut conf: config::Configuration = (*config::get()).clone(); let mut conf: config::Configuration = (*config::get()).clone();
for f in &t.extra_uplink_channels { for f in &t.extra_uplink_channels {
conf.regions[0] conf.regions[0]
@ -1246,6 +1247,17 @@ async fn run_test(t: &Test) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
device::partial_update(
t.dev_eui,
&device::DeviceChangeset {
dev_addr: Some(None),
device_session: Some(None),
..Default::default()
},
)
.await
.unwrap();
if let Some(f) = &t.before_func { if let Some(f) = &t.before_func {
f().await; f().await;
} }

View File

@ -6,14 +6,16 @@ use super::assert;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_profile, device_queue, device_session, gateway, reset_redis, tenant, device_profile, device_queue, gateway, reset_redis, tenant,
}; };
use crate::{gateway::backend as gateway_backend, integration, test, uplink}; use crate::{gateway::backend as gateway_backend, integration, test, uplink};
use chirpstack_api::{common, gw, integration as integration_pb, internal}; use chirpstack_api::{common, gw, integration as integration_pb, internal};
use lrwn::{AES128Key, EUI64}; use lrwn::{AES128Key, DevAddr, EUI64};
struct Test { struct Test {
name: String, name: String,
dev_eui_relay: EUI64,
dev_eui_relay_ed: EUI64,
device_queue_items_relay_ed: Vec<device_queue::DeviceQueueItem>, device_queue_items_relay_ed: Vec<device_queue::DeviceQueueItem>,
device_session_relay: Option<internal::DeviceSession>, device_session_relay: Option<internal::DeviceSession>,
device_session_relay_ed: Option<internal::DeviceSession>, device_session_relay_ed: Option<internal::DeviceSession>,
@ -85,6 +87,7 @@ async fn test_lorawan_10() {
device_profile_id: dp_relay.id, device_profile_id: dp_relay.id,
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]), dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([1, 1, 1, 1])),
..Default::default() ..Default::default()
}) })
.await .await
@ -96,6 +99,7 @@ async fn test_lorawan_10() {
device_profile_id: dp_relay_ed.id, device_profile_id: dp_relay_ed.id,
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]), dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
dev_addr: Some(DevAddr::from_be_bytes([2, 2, 2, 2])),
..Default::default() ..Default::default()
}) })
.await .await
@ -120,7 +124,6 @@ async fn test_lorawan_10() {
uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 5).unwrap(); uplink::helpers::set_uplink_modulation(&"eu868", &mut tx_info, 5).unwrap();
let ds_relay = internal::DeviceSession { let ds_relay = internal::DeviceSession {
dev_eui: dev_relay.dev_eui.to_vec(),
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
dev_addr: vec![1, 1, 1, 1], dev_addr: vec![1, 1, 1, 1],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -140,7 +143,6 @@ async fn test_lorawan_10() {
}; };
let ds_relay_ed = internal::DeviceSession { let ds_relay_ed = internal::DeviceSession {
dev_eui: dev_relay_ed.dev_eui.to_vec(),
mac_version: common::MacVersion::Lorawan104.into(), mac_version: common::MacVersion::Lorawan104.into(),
dev_addr: vec![2, 2, 2, 2], dev_addr: vec![2, 2, 2, 2],
f_nwk_s_int_key: vec![2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -439,6 +441,8 @@ async fn test_lorawan_10() {
let tests = vec![ let tests = vec![
Test { Test {
name: "relayed unconfirmed uplink".into(), name: "relayed unconfirmed uplink".into(),
dev_eui_relay: dev_relay.dev_eui,
dev_eui_relay_ed: dev_relay_ed.dev_eui,
device_queue_items_relay_ed: vec![], device_queue_items_relay_ed: vec![],
device_session_relay: Some(ds_relay.clone()), device_session_relay: Some(ds_relay.clone()),
device_session_relay_ed: Some(ds_relay_ed.clone()), device_session_relay_ed: Some(ds_relay_ed.clone()),
@ -503,6 +507,8 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "relayed confirmed uplink".into(), name: "relayed confirmed uplink".into(),
dev_eui_relay: dev_relay.dev_eui,
dev_eui_relay_ed: dev_relay_ed.dev_eui,
device_queue_items_relay_ed: vec![], device_queue_items_relay_ed: vec![],
device_session_relay: Some(ds_relay.clone()), device_session_relay: Some(ds_relay.clone()),
device_session_relay_ed: Some(ds_relay_ed.clone()), device_session_relay_ed: Some(ds_relay_ed.clone()),
@ -627,6 +633,8 @@ async fn test_lorawan_10() {
}, },
Test { Test {
name: "relayed unconfirmed uplink + adr_ack_req".into(), name: "relayed unconfirmed uplink + adr_ack_req".into(),
dev_eui_relay: dev_relay.dev_eui,
dev_eui_relay_ed: dev_relay_ed.dev_eui,
device_queue_items_relay_ed: vec![], device_queue_items_relay_ed: vec![],
device_session_relay: Some(ds_relay.clone()), device_session_relay: Some(ds_relay.clone()),
device_session_relay_ed: Some(ds_relay_ed.clone()), device_session_relay_ed: Some(ds_relay_ed.clone()),
@ -765,20 +773,30 @@ async fn run_test(t: &Test) {
integration::mock::reset().await; integration::mock::reset().await;
gateway_backend::mock::reset().await; gateway_backend::mock::reset().await;
device_queue::flush_for_dev_eui(&t.dev_eui_relay)
if let Some(ds) = &t.device_session_relay { .await
let _ = device_session::save(&ds).await.unwrap(); .unwrap();
device_queue::flush_for_dev_eui(&t.dev_eui_relay_ed)
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); .await
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); .unwrap();
} device::partial_update(
t.dev_eui_relay,
if let Some(ds) = &t.device_session_relay_ed { &device::DeviceChangeset {
let _ = device_session::save(&ds).await.unwrap(); device_session: Some(t.device_session_relay.clone()),
..Default::default()
let dev_eui = EUI64::from_slice(&ds.dev_eui).unwrap(); },
device_queue::flush_for_dev_eui(&dev_eui).await.unwrap(); )
} .await
.unwrap();
device::partial_update(
t.dev_eui_relay_ed,
&device::DeviceChangeset {
device_session: Some(t.device_session_relay_ed.clone()),
..Default::default()
},
)
.await
.unwrap();
for qi in &t.device_queue_items_relay_ed { for qi in &t.device_queue_items_relay_ed {
let _ = device_queue::enqueue_item(qi.clone()).await.unwrap(); let _ = device_queue::enqueue_item(qi.clone()).await.unwrap();

View File

@ -6,11 +6,11 @@ use super::assert;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_keys, device_profile, device_session, gateway, tenant, device_keys, device_profile, gateway, tenant,
}; };
use crate::{gateway::backend as gateway_backend, integration, test, uplink}; use crate::{gateway::backend as gateway_backend, integration, test, uplink};
use chirpstack_api::{common, gw, internal}; use chirpstack_api::{common, gw, internal};
use lrwn::{AES128Key, EUI64}; use lrwn::{AES128Key, DevAddr, EUI64};
#[tokio::test] #[tokio::test]
async fn test_lorawan_10() { async fn test_lorawan_10() {
@ -96,13 +96,8 @@ async fn test_lorawan_10() {
device_profile_id: dp_relay.id.clone(), device_profile_id: dp_relay.id.clone(),
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 2]), dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 2]),
enabled_class: DeviceClass::A, enabled_class: DeviceClass::A,
..Default::default() dev_addr: Some(DevAddr::from_be_bytes([4, 3, 2, 1])),
}) device_session: Some(internal::DeviceSession {
.await
.unwrap();
let ds_relay = internal::DeviceSession {
dev_eui: dev_relay.dev_eui.to_vec(),
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
dev_addr: vec![4, 3, 2, 1], dev_addr: vec![4, 3, 2, 1],
f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], f_nwk_s_int_key: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
@ -114,8 +109,13 @@ async fn test_lorawan_10() {
rx2_frequency: 869525000, rx2_frequency: 869525000,
region_config_id: "eu868".into(), region_config_id: "eu868".into(),
..Default::default() ..Default::default()
}; }),
device_session::save(&ds_relay).await.unwrap(); ..Default::default()
})
.await
.unwrap();
let ds_relay = dev_relay.get_device_session().unwrap();
let mut rx_info = gw::UplinkRxInfo { let mut rx_info = gw::UplinkRxInfo {
gateway_id: gw.gateway_id.to_string(), gateway_id: gw.gateway_id.to_string(),
@ -268,8 +268,6 @@ async fn test_lorawan_10() {
dev.dev_eui.clone(), dev.dev_eui.clone(),
internal::DeviceSession { internal::DeviceSession {
dev_addr: vec![1, 2, 3, 4], dev_addr: vec![1, 2, 3, 4],
dev_eui: vec![1, 1, 1, 1, 1, 1, 1, 1],
join_eui: vec![1, 2, 3, 4, 5, 6, 7, 8],
mac_version: common::MacVersion::Lorawan102.into(), mac_version: common::MacVersion::Lorawan102.into(),
f_nwk_s_int_key: vec![ f_nwk_s_int_key: vec![
146, 184, 94, 251, 180, 89, 48, 96, 236, 112, 106, 181, 94, 25, 215, 162, 146, 184, 94, 251, 180, 89, 48, 96, 236, 112, 106, 181, 94, 25, 215, 162,

View File

@ -17,12 +17,12 @@ use crate::storage::error::Error as StorageError;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_gateway, device_profile, device_queue, device_session, fields, device_gateway, device_profile, device_queue, fields,
helpers::get_all_device_data, helpers::get_all_device_data,
metrics, tenant, metrics, tenant,
}; };
use crate::{codec, config, downlink, integration, maccommand, region, stream}; use crate::{codec, config, downlink, integration, maccommand, region, stream};
use chirpstack_api::{integration as integration_pb, internal, stream as stream_pb}; use chirpstack_api::{common, integration as integration_pb, internal, stream as stream_pb};
use lrwn::{AES128Key, EUI64}; use lrwn::{AES128Key, EUI64};
pub struct Data { pub struct Data {
@ -40,7 +40,6 @@ pub struct Data {
retransmission: bool, retransmission: bool,
f_cnt_up_full: u32, f_cnt_up_full: u32,
tenant: Option<tenant::Tenant>, tenant: Option<tenant::Tenant>,
device_session: Option<internal::DeviceSession>,
device: Option<device::Device>, device: Option<device::Device>,
device_profile: Option<device_profile::DeviceProfile>, device_profile: Option<device_profile::DeviceProfile>,
application: Option<application::Application>, application: Option<application::Application>,
@ -50,6 +49,7 @@ pub struct Data {
must_send_downlink: bool, must_send_downlink: bool,
downlink_mac_commands: Vec<lrwn::MACCommandSet>, downlink_mac_commands: Vec<lrwn::MACCommandSet>,
device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>, device_gateway_rx_info: Option<internal::DeviceGatewayRxInfo>,
device_changeset: device::DeviceChangeset,
} }
impl Data { impl Data {
@ -99,7 +99,6 @@ impl Data {
reset: false, reset: false,
retransmission: false, retransmission: false,
tenant: None, tenant: None,
device_session: None,
device: None, device: None,
device_profile: None, device_profile: None,
application: None, application: None,
@ -109,10 +108,11 @@ impl Data {
must_send_downlink: false, must_send_downlink: false,
downlink_mac_commands: Vec::new(), downlink_mac_commands: Vec::new(),
device_gateway_rx_info: None, device_gateway_rx_info: None,
device_changeset: Default::default(),
}; };
ctx.handle_passive_roaming_device().await?; ctx.handle_passive_roaming_device().await?;
ctx.get_device_session().await?; ctx.get_device_for_phy_payload().await?;
ctx.get_device_data().await?; ctx.get_device_data().await?;
ctx.check_roaming_allowed()?; ctx.check_roaming_allowed()?;
@ -120,17 +120,16 @@ impl Data {
let span = tracing::Span::current(); let span = tracing::Span::current();
span.record("dev_eui", ctx.device.as_ref().unwrap().dev_eui.to_string()); span.record("dev_eui", ctx.device.as_ref().unwrap().dev_eui.to_string());
ctx.abort_on_device_is_disabled().await?;
ctx.set_device_info()?;
ctx.set_device_gateway_rx_info()?;
ctx.handle_retransmission_reset().await?;
ctx.set_scheduler_run_after().await?;
if !ctx._is_roaming() { if !ctx._is_roaming() {
// In case of roaming we do not know the gateways and therefore it must not be // In case of roaming we do not know the gateways and therefore it must not be
// filtered. // filtered.
ctx.filter_rx_info_by_tenant().await?; ctx.filter_rx_info_by_tenant().await?;
ctx.filter_rx_info_by_region_config_id()?; ctx.filter_rx_info_by_region_config_id()?;
} }
ctx.set_device_info()?;
ctx.set_device_gateway_rx_info()?;
ctx.handle_retransmission_reset().await?;
ctx.set_scheduler_run_after().await?;
ctx.decrypt_f_opts_mac_commands()?; ctx.decrypt_f_opts_mac_commands()?;
ctx.decrypt_frm_payload()?; ctx.decrypt_frm_payload()?;
ctx.log_uplink_frame_set().await?; ctx.log_uplink_frame_set().await?;
@ -148,7 +147,7 @@ impl Data {
ctx.detect_and_save_measurements().await?; ctx.detect_and_save_measurements().await?;
ctx.sync_uplink_f_cnt()?; ctx.sync_uplink_f_cnt()?;
ctx.set_region_config_id()?; ctx.set_region_config_id()?;
ctx.save_device_session().await?; ctx.update_device().await?;
ctx.handle_uplink_ack().await?; ctx.handle_uplink_ack().await?;
ctx.save_metrics().await?; ctx.save_metrics().await?;
@ -175,7 +174,6 @@ impl Data {
reset: false, reset: false,
retransmission: false, retransmission: false,
tenant: None, tenant: None,
device_session: None,
device: None, device: None,
device_profile: None, device_profile: None,
application: None, application: None,
@ -184,11 +182,11 @@ impl Data {
uplink_event: None, uplink_event: None,
must_send_downlink: false, must_send_downlink: false,
downlink_mac_commands: Vec::new(), downlink_mac_commands: Vec::new(),
device_changeset: Default::default(),
}; };
ctx.get_device_session_relayed().await?; ctx.get_device_for_phy_payload_relayed().await?;
ctx.get_device_data().await?; ctx.get_device_data().await?;
ctx.abort_on_device_is_disabled().await?;
ctx.set_device_info()?; ctx.set_device_info()?;
ctx.set_relay_rx_info()?; ctx.set_relay_rx_info()?;
ctx.handle_retransmission_reset().await?; ctx.handle_retransmission_reset().await?;
@ -204,7 +202,7 @@ impl Data {
ctx.detect_and_save_measurements().await?; ctx.detect_and_save_measurements().await?;
ctx.sync_uplink_f_cnt()?; ctx.sync_uplink_f_cnt()?;
ctx.set_region_config_id()?; ctx.set_region_config_id()?;
ctx.save_device_session().await?; ctx.update_device().await?;
ctx.handle_uplink_ack().await?; ctx.handle_uplink_ack().await?;
ctx.save_metrics_relayed().await?; ctx.save_metrics_relayed().await?;
ctx.start_downlink_data_flow_relayed().await?; ctx.start_downlink_data_flow_relayed().await?;
@ -230,8 +228,8 @@ impl Data {
Ok(()) Ok(())
} }
async fn get_device_session(&mut self) -> Result<(), Error> { async fn get_device_for_phy_payload(&mut self) -> Result<(), Error> {
trace!("Getting device-session for dev_addr"); trace!("Getting device for PhyPayload");
let dev_addr = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload { let dev_addr = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
pl.fhdr.devaddr pl.fhdr.devaddr
@ -239,7 +237,7 @@ impl Data {
return Err(Error::AnyhowError(anyhow!("No MacPayload in PhyPayload"))); return Err(Error::AnyhowError(anyhow!("No MacPayload in PhyPayload")));
}; };
match device_session::get_for_phypayload_and_incr_f_cnt_up( match device::get_for_phypayload_and_incr_f_cnt_up(
false, false,
&mut self.phy_payload, &mut self.phy_payload,
self.uplink_frame_set.dr, self.uplink_frame_set.dr,
@ -248,18 +246,18 @@ impl Data {
.await .await
{ {
Ok(v) => match v { Ok(v) => match v {
device_session::ValidationStatus::Ok(f_cnt, ds) => { device::ValidationStatus::Ok(f_cnt, d) => {
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
device_session::ValidationStatus::Retransmission(f_cnt, ds) => { device::ValidationStatus::Retransmission(f_cnt, d) => {
self.retransmission = true; self.retransmission = true;
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
device_session::ValidationStatus::Reset(f_cnt, ds) => { device::ValidationStatus::Reset(f_cnt, d) => {
self.reset = true; self.reset = true;
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
}, },
@ -289,8 +287,8 @@ impl Data {
Ok(()) Ok(())
} }
async fn get_device_session_relayed(&mut self) -> Result<(), Error> { async fn get_device_for_phy_payload_relayed(&mut self) -> Result<(), Error> {
trace!("Getting device-session for dev_addr (relayed)"); trace!("Getting device for PhyPayload (relayed)");
let relay_ctx = self.relay_context.as_ref().unwrap(); let relay_ctx = self.relay_context.as_ref().unwrap();
@ -307,27 +305,22 @@ impl Data {
dr, dr,
)? as u8; )? as u8;
match device_session::get_for_phypayload_and_incr_f_cnt_up( match device::get_for_phypayload_and_incr_f_cnt_up(true, &mut self.phy_payload, dr, ch)
true,
&mut self.phy_payload,
dr,
ch,
)
.await .await
{ {
Ok(v) => match v { Ok(v) => match v {
device_session::ValidationStatus::Ok(f_cnt, ds) => { device::ValidationStatus::Ok(f_cnt, d) => {
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
device_session::ValidationStatus::Retransmission(f_cnt, ds) => { device::ValidationStatus::Retransmission(f_cnt, d) => {
self.retransmission = true; self.retransmission = true;
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
device_session::ValidationStatus::Reset(f_cnt, ds) => { device::ValidationStatus::Reset(f_cnt, d) => {
self.reset = true; self.reset = true;
self.device_session = Some(ds); self.device = Some(d);
self.f_cnt_up_full = f_cnt; self.f_cnt_up_full = f_cnt;
} }
}, },
@ -353,8 +346,9 @@ impl Data {
async fn get_device_data(&mut self) -> Result<()> { async fn get_device_data(&mut self) -> Result<()> {
trace!("Getting device data"); trace!("Getting device data");
let dev_eui = lrwn::EUI64::from_slice(&self.device_session.as_ref().unwrap().dev_eui)?;
let (dev, app, t, dp) = get_all_device_data(dev_eui).await?; let dev_eui = self.device.as_ref().unwrap().dev_eui;
let (_, app, t, dp) = get_all_device_data(dev_eui).await?;
if dp.region != self.uplink_frame_set.region_common_name { if dp.region != self.uplink_frame_set.region_common_name {
return Err(anyhow!("Invalid device-profile region")); return Err(anyhow!("Invalid device-profile region"));
@ -363,7 +357,6 @@ impl Data {
self.tenant = Some(t); self.tenant = Some(t);
self.application = Some(app); self.application = Some(app);
self.device_profile = Some(dp); self.device_profile = Some(dp);
self.device = Some(dev);
Ok(()) Ok(())
} }
@ -425,9 +418,10 @@ impl Data {
fn set_device_gateway_rx_info(&mut self) -> Result<()> { fn set_device_gateway_rx_info(&mut self) -> Result<()> {
trace!("Setting gateway rx-info for device"); trace!("Setting gateway rx-info for device");
let d = self.device.as_ref().unwrap();
self.device_gateway_rx_info = Some(internal::DeviceGatewayRxInfo { self.device_gateway_rx_info = Some(internal::DeviceGatewayRxInfo {
dev_eui: self.device_session.as_ref().unwrap().dev_eui.clone(), dev_eui: d.dev_eui.to_vec(),
dr: self.uplink_frame_set.dr as u32, dr: self.uplink_frame_set.dr as u32,
items: self items: self
.uplink_frame_set .uplink_frame_set
@ -469,24 +463,6 @@ impl Data {
Ok(()) Ok(())
} }
async fn abort_on_device_is_disabled(&self) -> Result<(), Error> {
let device = self.device.as_ref().unwrap();
if device.is_disabled {
// Restore the device-session in case the device is disabled.
// This is because during the fcnt validation, we immediately store the
// device-session with incremented fcnt to avoid race conditions.
device_session::save(self.device_session.as_ref().unwrap())
.await
.context("Savel device-session")?;
info!(dev_eui = %device.dev_eui, "Device is disabled, aborting flow");
return Err(Error::Abort);
}
Ok(())
}
async fn handle_retransmission_reset(&self) -> Result<(), Error> { async fn handle_retransmission_reset(&self) -> Result<(), Error> {
trace!("Handle retransmission and reset"); trace!("Handle retransmission and reset");
let dev = self.device.as_ref().unwrap(); let dev = self.device.as_ref().unwrap();
@ -555,7 +531,13 @@ impl Data {
if dev.scheduler_run_after.is_none() if dev.scheduler_run_after.is_none()
|| scheduler_run_after > dev.scheduler_run_after.unwrap() || scheduler_run_after > dev.scheduler_run_after.unwrap()
{ {
*dev = device::set_scheduler_run_after(&dev.dev_eui, Some(scheduler_run_after)) *dev = device::partial_update(
dev.dev_eui,
&device::DeviceChangeset {
scheduler_run_after: Some(Some(scheduler_run_after)),
..Default::default()
},
)
.await?; .await?;
} }
} }
@ -575,9 +557,15 @@ impl Data {
// Restore the device-session in case of an error (no gateways available). // Restore the device-session in case of an error (no gateways available).
// This is because during the fcnt validation, we immediately store the // This is because during the fcnt validation, we immediately store the
// device-session with incremented fcnt to avoid race conditions. // device-session with incremented fcnt to avoid race conditions.
device_session::save(self.device_session.as_ref().unwrap()) let d = self.device.as_ref().unwrap();
.await device::partial_update(
.context("Save device-session")?; d.dev_eui,
&device::DeviceChangeset {
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
Err(v) Err(v)
} }
@ -597,7 +585,13 @@ impl Data {
fn decrypt_f_opts_mac_commands(&mut self) -> Result<()> { fn decrypt_f_opts_mac_commands(&mut self) -> Result<()> {
trace!("Decrypting mac-commands"); trace!("Decrypting mac-commands");
let ds = self.device_session.as_ref().unwrap(); let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
if ds.mac_version().to_string().starts_with("1.0") { if ds.mac_version().to_string().starts_with("1.0") {
if let Err(e) = self.phy_payload.decode_f_opts_to_mac_commands() { if let Err(e) = self.phy_payload.decode_f_opts_to_mac_commands() {
// This avoids failing in case of a corrupted mac-command in the frm_payload. // This avoids failing in case of a corrupted mac-command in the frm_payload.
@ -616,7 +610,13 @@ impl Data {
fn decrypt_frm_payload(&mut self) -> Result<()> { fn decrypt_frm_payload(&mut self) -> Result<()> {
trace!("Decrypting FRMPayload"); trace!("Decrypting FRMPayload");
let ds = self.device_session.as_ref().unwrap(); let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
let mut f_port = 0; let mut f_port = 0;
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload { if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
@ -656,7 +656,13 @@ impl Data {
fn set_adr(&mut self) -> Result<()> { fn set_adr(&mut self) -> Result<()> {
trace!("Set ADR flag in device-session"); trace!("Set ADR flag in device-session");
let ds = self.device_session.as_mut().unwrap(); let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload { if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
ds.adr = pl.fhdr.f_ctrl.adr; ds.adr = pl.fhdr.f_ctrl.adr;
} }
@ -666,9 +672,13 @@ impl Data {
async fn set_uplink_data_rate(&mut self) -> Result<()> { async fn set_uplink_data_rate(&mut self) -> Result<()> {
trace!("Set uplink data-rate and reset tx-power on change"); trace!("Set uplink data-rate and reset tx-power on change");
let device = self.device.as_mut().unwrap(); let device = self.device.as_mut().unwrap();
*device = device::set_last_seen_dr(&device.dev_eui, self.uplink_frame_set.dr).await?;
let ds = self.device_session.as_mut().unwrap(); self.device_changeset.last_seen_at = Some(Some(Utc::now()));
if device.dr.is_none() || self.uplink_frame_set.dr as i16 != device.dr.unwrap_or_default() {
self.device_changeset.dr = Some(Some(self.uplink_frame_set.dr.into()));
}
let ds = device.get_device_session_mut()?;
// The node changed its data-rate. Possibly the node did also reset its // The node changed its data-rate. Possibly the node did also reset its
// tx-power to max power. Because of this, we need to reset the tx-power // tx-power to max power. Because of this, we need to reset the tx-power
// and the uplink history at the network-server side too. // and the uplink history at the network-server side too.
@ -677,6 +687,7 @@ impl Data {
ds.uplink_adr_history = Vec::new(); ds.uplink_adr_history = Vec::new();
} }
ds.dr = self.uplink_frame_set.dr as u32; ds.dr = self.uplink_frame_set.dr as u32;
Ok(()) Ok(())
} }
@ -684,9 +695,13 @@ impl Data {
trace!("Set relayed uplink data-rate and reset tx-power on change"); trace!("Set relayed uplink data-rate and reset tx-power on change");
let device = self.device.as_mut().unwrap(); let device = self.device.as_mut().unwrap();
let relay_ctx = self.relay_context.as_ref().unwrap(); let relay_ctx = self.relay_context.as_ref().unwrap();
*device = device::set_last_seen_dr(&device.dev_eui, self.uplink_frame_set.dr).await?;
let ds = self.device_session.as_mut().unwrap(); self.device_changeset.last_seen_at = Some(Some(Utc::now()));
if device.dr.is_none() || self.uplink_frame_set.dr as i16 != device.dr.unwrap_or_default() {
self.device_changeset.dr = Some(Some(self.uplink_frame_set.dr.into()));
}
let ds = device.get_device_session_mut()?;
// The node changed its data-rate. Possibly the node did also reset its // The node changed its data-rate. Possibly the node did also reset its
// tx-power to max power. Because of this, we need to reset the tx-power // tx-power to max power. Because of this, we need to reset the tx-power
// and the uplink history at the network-server side too. // and the uplink history at the network-server side too.
@ -717,7 +732,7 @@ impl Data {
// Update if the enabled class has changed. // Update if the enabled class has changed.
if dev.enabled_class != enabled_class { if dev.enabled_class != enabled_class {
*dev = device::set_enabled_class(&dev.dev_eui, enabled_class).await?; self.device_changeset.enabled_class = Some(enabled_class);
} }
Ok(()) Ok(())
@ -770,11 +785,12 @@ impl Data {
// device did not reset these). // device did not reset these).
fn reset_channels_on_adr_ack_req(&mut self) -> Result<()> { fn reset_channels_on_adr_ack_req(&mut self) -> Result<()> {
trace!("Reset channels on adr ack req"); trace!("Reset channels on adr ack req");
let d = self.device.as_mut().unwrap();
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload { if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
if pl.fhdr.f_ctrl.adr_ack_req { if pl.fhdr.f_ctrl.adr_ack_req {
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?; let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let ds = self.device_session.as_mut().unwrap(); let ds = d.device_session.as_mut().unwrap();
// We reset the device-session enabled_uplink_channel_indices and // We reset the device-session enabled_uplink_channel_indices and
// extra_uplink_channels. On the downlink path, the mac-command handling will // extra_uplink_channels. On the downlink path, the mac-command handling will
@ -804,8 +820,7 @@ impl Data {
self.tenant.as_ref().unwrap(), self.tenant.as_ref().unwrap(),
self.application.as_ref().unwrap(), self.application.as_ref().unwrap(),
self.device_profile.as_ref().unwrap(), self.device_profile.as_ref().unwrap(),
self.device.as_ref().unwrap(), self.device.as_mut().unwrap(),
self.device_session.as_mut().unwrap(),
) )
.await .await
.context("Handle uplink mac-commands")?; .context("Handle uplink mac-commands")?;
@ -822,8 +837,7 @@ impl Data {
self.tenant.as_ref().unwrap(), self.tenant.as_ref().unwrap(),
self.application.as_ref().unwrap(), self.application.as_ref().unwrap(),
self.device_profile.as_ref().unwrap(), self.device_profile.as_ref().unwrap(),
self.device.as_ref().unwrap(), self.device.as_mut().unwrap(),
self.device_session.as_mut().unwrap(),
) )
.await .await
.context("Handle uplink mac-commands")?; .context("Handle uplink mac-commands")?;
@ -847,7 +861,13 @@ impl Data {
} }
fn append_meta_data_to_uplink_history(&mut self) -> Result<()> { fn append_meta_data_to_uplink_history(&mut self) -> Result<()> {
let ds = self.device_session.as_mut().unwrap(); let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
// ignore re-transmissions we don't know the source of the // ignore re-transmissions we don't know the source of the
// re-transmission (it might be a replay-attack) // re-transmission (it might be a replay-attack)
@ -892,7 +912,13 @@ impl Data {
fn append_meta_data_to_uplink_history_relayed(&mut self) -> Result<()> { fn append_meta_data_to_uplink_history_relayed(&mut self) -> Result<()> {
trace!("Apping meta-data of relayed uplink to upink history"); trace!("Apping meta-data of relayed uplink to upink history");
let ds = self.device_session.as_mut().unwrap(); let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
let relay_ctx = self.relay_context.as_ref().unwrap(); let relay_ctx = self.relay_context.as_ref().unwrap();
// ignore re-transmissions we don't know the source of the // ignore re-transmissions we don't know the source of the
@ -929,7 +955,7 @@ impl Data {
let app = self.application.as_ref().unwrap(); let app = self.application.as_ref().unwrap();
let dp = self.device_profile.as_ref().unwrap(); let dp = self.device_profile.as_ref().unwrap();
let dev = self.device.as_ref().unwrap(); let dev = self.device.as_ref().unwrap();
let ds = self.device_session.as_ref().unwrap(); let ds = dev.get_device_session()?;
let mac = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload { let mac = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
pl pl
} else { } else {
@ -955,7 +981,7 @@ impl Data {
rx_info: self.uplink_frame_set.rx_info_set.clone(), rx_info: self.uplink_frame_set.rx_info_set.clone(),
tx_info: Some(self.uplink_frame_set.tx_info.clone()), tx_info: Some(self.uplink_frame_set.tx_info.clone()),
join_server_context: if self._is_end_to_end_encrypted() { join_server_context: if self._is_end_to_end_encrypted() {
Some(integration_pb::JoinServerContext { Some(common::JoinServerContext {
session_key_id: hex::encode(&ds.js_session_key_id), session_key_id: hex::encode(&ds.js_session_key_id),
app_s_key: ds.app_s_key.clone(), app_s_key: ds.app_s_key.clone(),
}) })
@ -1092,7 +1118,8 @@ impl Data {
// required. // required.
fn sync_uplink_f_cnt(&mut self) -> Result<()> { fn sync_uplink_f_cnt(&mut self) -> Result<()> {
trace!("Syncing uplink frame-counter"); trace!("Syncing uplink frame-counter");
let ds = self.device_session.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.f_cnt_up = self.f_cnt_up_full + 1; ds.f_cnt_up = self.f_cnt_up_full + 1;
Ok(()) Ok(())
} }
@ -1102,16 +1129,19 @@ impl Data {
// value is not set initially. // value is not set initially.
fn set_region_config_id(&mut self) -> Result<()> { fn set_region_config_id(&mut self) -> Result<()> {
trace!("Setting region_config_id to device-session"); trace!("Setting region_config_id to device-session");
let ds = self.device_session.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.region_config_id = self.uplink_frame_set.region_config_id.clone(); ds.region_config_id = self.uplink_frame_set.region_config_id.clone();
Ok(()) Ok(())
} }
async fn save_device_session(&self) -> Result<()> { async fn update_device(&mut self) -> Result<()> {
trace!("Saving device-session"); trace!("Updating device");
device_session::save(self.device_session.as_ref().unwrap())
.await let d = self.device.as_mut().unwrap();
.context("Save device-session")?; self.device_changeset.device_session = Some(d.device_session.clone());
*d = device::partial_update(d.dev_eui, &self.device_changeset).await?;
Ok(()) Ok(())
} }
@ -1265,7 +1295,6 @@ impl Data {
self.application.as_ref().cloned().unwrap(), self.application.as_ref().cloned().unwrap(),
self.device_profile.as_ref().cloned().unwrap(), self.device_profile.as_ref().cloned().unwrap(),
self.device.as_ref().cloned().unwrap(), self.device.as_ref().cloned().unwrap(),
self.device_session.as_ref().cloned().unwrap(),
pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink, pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink,
self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp, self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp,
self.downlink_mac_commands.clone(), self.downlink_mac_commands.clone(),
@ -1291,7 +1320,6 @@ impl Data {
self.application.as_ref().cloned().unwrap(), self.application.as_ref().cloned().unwrap(),
self.device_profile.as_ref().cloned().unwrap(), self.device_profile.as_ref().cloned().unwrap(),
self.device.as_ref().cloned().unwrap(), self.device.as_ref().cloned().unwrap(),
self.device_session.as_ref().cloned().unwrap(),
pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink, pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink,
self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp, self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp,
self.downlink_mac_commands.clone(), self.downlink_mac_commands.clone(),
@ -1314,7 +1342,6 @@ impl Data {
req: pl.clone(), req: pl.clone(),
device: self.device.as_ref().unwrap().clone(), device: self.device.as_ref().unwrap().clone(),
device_profile: self.device_profile.as_ref().unwrap().clone(), device_profile: self.device_profile.as_ref().unwrap().clone(),
device_session: self.device_session.as_ref().unwrap().clone(),
must_ack: self.phy_payload.mhdr.m_type must_ack: self.phy_payload.mhdr.m_type
== lrwn::MType::ConfirmedDataUp, == lrwn::MType::ConfirmedDataUp,
must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req, must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req,
@ -1329,7 +1356,6 @@ impl Data {
req: pl.clone(), req: pl.clone(),
device: self.device.as_ref().unwrap().clone(), device: self.device.as_ref().unwrap().clone(),
device_profile: self.device_profile.as_ref().unwrap().clone(), device_profile: self.device_profile.as_ref().unwrap().clone(),
device_session: self.device_session.as_ref().unwrap().clone(),
must_ack: self.phy_payload.mhdr.m_type must_ack: self.phy_payload.mhdr.m_type
== lrwn::MType::ConfirmedDataUp, == lrwn::MType::ConfirmedDataUp,
must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req, must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req,
@ -1369,7 +1395,13 @@ impl Data {
} }
fn _is_end_to_end_encrypted(&self) -> bool { fn _is_end_to_end_encrypted(&self) -> bool {
let ds = self.device_session.as_ref().unwrap(); let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
if !ds.js_session_key_id.is_empty() { if !ds.js_session_key_id.is_empty() {
return true; return true;

View File

@ -6,8 +6,8 @@ use chrono::{DateTime, Local, Utc};
use tracing::{error, info, span, trace, warn, Instrument, Level}; use tracing::{error, info, span, trace, warn, Instrument, Level};
use lrwn::{ use lrwn::{
keys, AES128Key, CFList, DLSettings, DevAddr, JoinAcceptPayload, JoinRequestPayload, JoinType, keys, AES128Key, CFList, DLSettings, JoinAcceptPayload, JoinRequestPayload, JoinType, MType,
MType, Major, Payload, PhyPayload, MHDR, Major, Payload, PhyPayload, MHDR,
}; };
use super::error::Error; use super::error::Error;
@ -20,7 +20,6 @@ use super::{
use crate::api::{backend::get_async_receiver, helpers::ToProto}; use crate::api::{backend::get_async_receiver, helpers::ToProto};
use crate::backend::{joinserver, keywrap, roaming}; use crate::backend::{joinserver, keywrap, roaming};
use crate::helpers::errors::PrintFullError; use crate::helpers::errors::PrintFullError;
use crate::storage::device_session;
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
@ -40,12 +39,10 @@ pub struct JoinRequest {
join_request: Option<JoinRequestPayload>, join_request: Option<JoinRequestPayload>,
join_accept: Option<PhyPayload>, join_accept: Option<PhyPayload>,
device: Option<device::Device>, device: Option<device::Device>,
device_session: Option<internal::DeviceSession>,
application: Option<application::Application>, application: Option<application::Application>,
tenant: Option<tenant::Tenant>, tenant: Option<tenant::Tenant>,
device_profile: Option<device_profile::DeviceProfile>, device_profile: Option<device_profile::DeviceProfile>,
device_keys: Option<device_keys::DeviceKeys>, device_keys: Option<device_keys::DeviceKeys>,
dev_addr: Option<DevAddr>,
device_info: Option<integration_pb::DeviceInfo>, device_info: Option<integration_pb::DeviceInfo>,
relay_rx_info: Option<integration_pb::UplinkRelayRxInfo>, relay_rx_info: Option<integration_pb::UplinkRelayRxInfo>,
f_nwk_s_int_key: Option<AES128Key>, f_nwk_s_int_key: Option<AES128Key>,
@ -96,12 +93,10 @@ impl JoinRequest {
js_client: None, js_client: None,
join_request: None, join_request: None,
device: None, device: None,
device_session: None,
application: None, application: None,
tenant: None, tenant: None,
device_profile: None, device_profile: None,
device_keys: None, device_keys: None,
dev_addr: None,
join_accept: None, join_accept: None,
device_info: None, device_info: None,
relay_rx_info: None, relay_rx_info: None,
@ -130,7 +125,7 @@ impl JoinRequest {
ctx.abort_on_relay_only_comm()?; ctx.abort_on_relay_only_comm()?;
ctx.log_uplink_frame_set().await?; ctx.log_uplink_frame_set().await?;
ctx.abort_on_otaa_is_disabled()?; ctx.abort_on_otaa_is_disabled()?;
ctx.get_random_dev_addr()?; ctx.set_random_dev_addr()?;
if ctx.js_client.is_some() { if ctx.js_client.is_some() {
// Using join-server // Using join-server
ctx.get_join_accept_from_js().await?; ctx.get_join_accept_from_js().await?;
@ -141,11 +136,10 @@ impl JoinRequest {
ctx.construct_join_accept_and_set_keys()?; ctx.construct_join_accept_and_set_keys()?;
} }
ctx.log_uplink_meta().await?; ctx.log_uplink_meta().await?;
ctx.create_device_session().await?; ctx.set_device_session().await?;
ctx.flush_device_queue().await?; ctx.flush_device_queue().await?;
ctx.set_device_mode().await?; ctx.set_device_mode().await?;
ctx.set_dev_addr().await?; ctx.update_device().await?;
ctx.set_join_eui().await?;
ctx.start_downlink_join_accept_flow().await?; ctx.start_downlink_join_accept_flow().await?;
ctx.send_join_event().await?; ctx.send_join_event().await?;
@ -159,12 +153,10 @@ impl JoinRequest {
js_client: None, js_client: None,
join_request: None, join_request: None,
device: None, device: None,
device_session: None,
application: None, application: None,
tenant: None, tenant: None,
device_profile: None, device_profile: None,
device_keys: None, device_keys: None,
dev_addr: None,
join_accept: None, join_accept: None,
device_info: None, device_info: None,
relay_rx_info: None, relay_rx_info: None,
@ -183,7 +175,7 @@ impl JoinRequest {
ctx.abort_on_device_is_disabled()?; ctx.abort_on_device_is_disabled()?;
ctx.abort_on_otaa_is_disabled()?; ctx.abort_on_otaa_is_disabled()?;
ctx.abort_on_relay_only_comm()?; ctx.abort_on_relay_only_comm()?;
ctx.get_random_dev_addr()?; ctx.set_random_dev_addr()?;
if ctx.js_client.is_some() { if ctx.js_client.is_some() {
// Using join-server // Using join-server
ctx.get_join_accept_from_js().await?; ctx.get_join_accept_from_js().await?;
@ -193,11 +185,10 @@ impl JoinRequest {
ctx.validate_dev_nonce_and_get_device_keys().await?; ctx.validate_dev_nonce_and_get_device_keys().await?;
ctx.construct_join_accept_and_set_keys()?; ctx.construct_join_accept_and_set_keys()?;
} }
ctx.create_device_session().await?; ctx.set_device_session().await?;
ctx.flush_device_queue().await?; ctx.flush_device_queue().await?;
ctx.set_device_mode().await?; ctx.set_device_mode().await?;
ctx.set_dev_addr().await?; ctx.update_device().await?;
ctx.set_join_eui().await?;
ctx.start_downlink_join_accept_flow_relayed().await?; ctx.start_downlink_join_accept_flow_relayed().await?;
ctx.send_join_event().await?; ctx.send_join_event().await?;
@ -514,8 +505,10 @@ impl JoinRequest {
Ok(()) Ok(())
} }
fn get_random_dev_addr(&mut self) -> Result<()> { fn set_random_dev_addr(&mut self) -> Result<()> {
self.dev_addr = Some(get_random_dev_addr()); trace!("Setting random DevAddr");
let d = self.device.as_mut().unwrap();
d.dev_addr = Some(get_random_dev_addr());
Ok(()) Ok(())
} }
@ -550,7 +543,7 @@ impl JoinRequest {
mac_version: dp.mac_version.to_string(), mac_version: dp.mac_version.to_string(),
phy_payload: phy_b, phy_payload: phy_b,
dev_eui: dev.dev_eui.to_vec(), dev_eui: dev.dev_eui.to_vec(),
dev_addr: self.dev_addr.unwrap().to_vec(), dev_addr: dev.dev_addr.unwrap().to_vec(),
dl_settings: dl_settings.to_le_bytes()?.to_vec(), dl_settings: dl_settings.to_le_bytes()?.to_vec(),
rx_delay: region_network.rx1_delay, rx_delay: region_network.rx1_delay,
cf_list: match region_conf.get_cf_list(dp.mac_version) { cf_list: match region_conf.get_cf_list(dp.mac_version) {
@ -619,6 +612,7 @@ impl JoinRequest {
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?; let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let join_request = self.join_request.as_ref().unwrap(); let join_request = self.join_request.as_ref().unwrap();
let d = self.device.as_ref().unwrap();
let dk = self.device_keys.as_mut().unwrap(); let dk = self.device_keys.as_mut().unwrap();
let join_nonce = dk.join_nonce - 1; // this was incremented on validation let join_nonce = dk.join_nonce - 1; // this was incremented on validation
@ -643,7 +637,7 @@ impl JoinRequest {
payload: Payload::JoinAccept(JoinAcceptPayload { payload: Payload::JoinAccept(JoinAcceptPayload {
join_nonce: join_nonce as u32, join_nonce: join_nonce as u32,
home_netid: conf.network.net_id, home_netid: conf.network.net_id,
devaddr: self.dev_addr.unwrap(), devaddr: d.dev_addr.unwrap(),
dl_settings: DLSettings { dl_settings: DLSettings {
opt_neg, opt_neg,
rx2_dr: region_network.rx2_dr, rx2_dr: region_network.rx2_dr,
@ -768,21 +762,18 @@ impl JoinRequest {
Ok(()) Ok(())
} }
async fn create_device_session(&mut self) -> Result<()> { async fn set_device_session(&mut self) -> Result<()> {
trace!("Creating device-session"); trace!("Setting device-session");
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?; let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?; let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?;
let device = self.device.as_ref().unwrap(); let device = self.device.as_mut().unwrap();
let device_profile = self.device_profile.as_ref().unwrap(); let device_profile = self.device_profile.as_ref().unwrap();
let join_request = self.join_request.as_ref().unwrap();
let mut ds = internal::DeviceSession { let mut ds = internal::DeviceSession {
region_config_id: self.uplink_frame_set.region_config_id.clone(), region_config_id: self.uplink_frame_set.region_config_id.clone(),
dev_eui: device.dev_eui.to_be_bytes().to_vec(), dev_addr: device.dev_addr.unwrap().to_be_bytes().to_vec(),
dev_addr: self.dev_addr.unwrap().to_be_bytes().to_vec(),
join_eui: join_request.join_eui.to_be_bytes().to_vec(),
f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(), f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(),
s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(), s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(),
nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(), nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(),
@ -847,11 +838,7 @@ impl JoinRequest {
None => {} None => {}
} }
device_session::save(&ds) device.device_session = Some(ds);
.await
.context("Saving device-session failed")?;
self.device_session = Some(ds);
Ok(()) Ok(())
} }
@ -870,30 +857,36 @@ impl JoinRequest {
async fn set_device_mode(&mut self) -> Result<()> { async fn set_device_mode(&mut self) -> Result<()> {
let dp = self.device_profile.as_ref().unwrap(); let dp = self.device_profile.as_ref().unwrap();
let device = self.device.as_mut().unwrap(); let d = self.device.as_mut().unwrap();
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C. // LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") { if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::C).await?; d.enabled_class = DeviceClass::C;
} else { } else {
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::A).await?; d.enabled_class = DeviceClass::A;
} }
Ok(()) Ok(())
} }
async fn set_dev_addr(&mut self) -> Result<()> { async fn update_device(&mut self) -> Result<()> {
trace!("Setting DevAddr"); trace!("Updating device");
let dev = self.device.as_mut().unwrap();
*dev = device::set_dev_addr(dev.dev_eui, self.dev_addr.unwrap()).await?;
Ok(())
}
async fn set_join_eui(&mut self) -> Result<()> {
trace!("Setting JoinEUI");
let dev = self.device.as_mut().unwrap();
let req = self.join_request.as_ref().unwrap(); let req = self.join_request.as_ref().unwrap();
let d = self.device.as_mut().unwrap();
*dev = device::set_join_eui(dev.dev_eui, req.join_eui).await?; *d = device::partial_update(
d.dev_eui,
&device::DeviceChangeset {
enabled_class: Some(d.enabled_class),
dev_addr: Some(d.dev_addr),
secondary_dev_addr: Some(None),
join_eui: Some(req.join_eui),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
Ok(()) Ok(())
} }
@ -904,7 +897,6 @@ impl JoinRequest {
&self.uplink_frame_set, &self.uplink_frame_set,
self.tenant.as_ref().unwrap(), self.tenant.as_ref().unwrap(),
self.device.as_ref().unwrap(), self.device.as_ref().unwrap(),
self.device_session.as_ref().unwrap(),
self.join_accept.as_ref().unwrap(), self.join_accept.as_ref().unwrap(),
) )
.await?; .await?;
@ -918,7 +910,6 @@ impl JoinRequest {
&self.uplink_frame_set, &self.uplink_frame_set,
self.tenant.as_ref().unwrap(), self.tenant.as_ref().unwrap(),
self.device.as_ref().unwrap(), self.device.as_ref().unwrap(),
self.device_session.as_ref().unwrap(),
self.join_accept.as_ref().unwrap(), self.join_accept.as_ref().unwrap(),
) )
.await?; .await?;
@ -939,9 +930,9 @@ impl JoinRequest {
time: Some(ts.into()), time: Some(ts.into()),
device_info: self.device_info.clone(), device_info: self.device_info.clone(),
relay_rx_info: self.relay_rx_info.clone(), relay_rx_info: self.relay_rx_info.clone(),
dev_addr: self.dev_addr.as_ref().unwrap().to_string(), dev_addr: dev.dev_addr.unwrap().to_string(),
join_server_context: if !self.js_session_key_id.is_empty() { join_server_context: if !self.js_session_key_id.is_empty() {
Some(integration_pb::JoinServerContext { Some(common::JoinServerContext {
app_s_key: None, app_s_key: None,
session_key_id: hex::encode(&self.js_session_key_id), session_key_id: hex::encode(&self.js_session_key_id),
}) })
@ -949,7 +940,7 @@ impl JoinRequest {
if app_s_key.kek_label.is_empty() { if app_s_key.kek_label.is_empty() {
None None
} else { } else {
Some(integration_pb::JoinServerContext { Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope { app_s_key: Some(common::KeyEnvelope {
kek_label: app_s_key.kek_label.clone(), kek_label: app_s_key.kek_label.clone(),
aes_key: app_s_key.aes_key.clone(), aes_key: app_s_key.aes_key.clone(),

View File

@ -10,7 +10,7 @@ use crate::backend::{joinserver, keywrap, roaming};
use crate::storage::{ use crate::storage::{
application, application,
device::{self, DeviceClass}, device::{self, DeviceClass},
device_keys, device_profile, device_queue, device_session, device_keys, device_profile, device_queue,
error::Error as StorageError, error::Error as StorageError,
helpers::get_all_device_data, helpers::get_all_device_data,
metrics, tenant, metrics, tenant,
@ -28,7 +28,6 @@ pub struct JoinRequest {
join_request: Option<lrwn::JoinRequestPayload>, join_request: Option<lrwn::JoinRequestPayload>,
join_accept: Option<lrwn::PhyPayload>, join_accept: Option<lrwn::PhyPayload>,
device: Option<device::Device>, device: Option<device::Device>,
device_session: Option<internal::DeviceSession>,
js_client: Option<Arc<backend::Client>>, js_client: Option<Arc<backend::Client>>,
application: Option<application::Application>, application: Option<application::Application>,
tenant: Option<tenant::Tenant>, tenant: Option<tenant::Tenant>,
@ -66,7 +65,6 @@ impl JoinRequest {
join_request: None, join_request: None,
join_accept: None, join_accept: None,
device: None, device: None,
device_session: None,
js_client: None, js_client: None,
application: None, application: None,
tenant: None, tenant: None,
@ -99,10 +97,9 @@ impl JoinRequest {
ctx.construct_join_accept_and_set_keys()?; ctx.construct_join_accept_and_set_keys()?;
} }
ctx.log_uplink_meta().await?; ctx.log_uplink_meta().await?;
ctx.create_device_session().await?; ctx.set_device_session().await?;
ctx.flush_device_queue().await?; ctx.flush_device_queue().await?;
ctx.set_device_mode().await?; ctx.update_device().await?;
ctx.set_join_eui().await?;
ctx.send_join_event().await?; ctx.send_join_event().await?;
ctx.set_pr_start_ans_payload()?; ctx.set_pr_start_ans_payload()?;
@ -562,21 +559,18 @@ impl JoinRequest {
Ok(()) Ok(())
} }
async fn create_device_session(&mut self) -> Result<()> { async fn set_device_session(&mut self) -> Result<()> {
trace!("Creating device-session"); trace!("Setting device-session");
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?; let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?; let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?;
let device = self.device.as_ref().unwrap(); let device = self.device.as_mut().unwrap();
let device_profile = self.device_profile.as_ref().unwrap(); let device_profile = self.device_profile.as_ref().unwrap();
let join_request = self.join_request.as_ref().unwrap();
let mut ds = internal::DeviceSession { let mut ds = internal::DeviceSession {
region_config_id: self.uplink_frame_set.region_config_id.clone(), region_config_id: self.uplink_frame_set.region_config_id.clone(),
dev_eui: device.dev_eui.to_be_bytes().to_vec(),
dev_addr: self.dev_addr.unwrap().to_be_bytes().to_vec(), dev_addr: self.dev_addr.unwrap().to_be_bytes().to_vec(),
join_eui: join_request.join_eui.to_be_bytes().to_vec(),
f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(), f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(),
s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(), s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(),
nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(), nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(),
@ -627,11 +621,7 @@ impl JoinRequest {
} }
} }
device_session::save(&ds) device.device_session = Some(ds);
.await
.context("Saving device-session failed")?;
self.device_session = Some(ds);
Ok(()) Ok(())
} }
@ -648,25 +638,37 @@ impl JoinRequest {
Ok(()) Ok(())
} }
async fn set_device_mode(&mut self) -> Result<()> { async fn update_device(&mut self) -> Result<()> {
trace!("Updating device");
let dp = self.device_profile.as_ref().unwrap(); let dp = self.device_profile.as_ref().unwrap();
let device = self.device.as_mut().unwrap(); let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C. self.device = Some(
device::partial_update(
self.device.as_ref().unwrap().dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(ds.clone())),
join_eui: Some(self.join_request.as_ref().unwrap().join_eui),
dev_addr: Some(Some(self.dev_addr.unwrap())),
secondary_dev_addr: Some(None),
enabled_class: Some(
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") { if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::C).await?; DeviceClass::C
} else { } else {
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::A).await?; DeviceClass::A
} },
Ok(()) ),
} ..Default::default()
},
async fn set_join_eui(&mut self) -> Result<()> { )
trace!("Setting JoinEUI"); .await?,
let dev = self.device.as_mut().unwrap(); );
let req = self.join_request.as_ref().unwrap();
*dev = device::set_join_eui(dev.dev_eui, req.join_eui).await?;
Ok(()) Ok(())
} }
@ -687,7 +689,7 @@ impl JoinRequest {
relay_rx_info: None, relay_rx_info: None,
dev_addr: self.dev_addr.as_ref().unwrap().to_string(), dev_addr: self.dev_addr.as_ref().unwrap().to_string(),
join_server_context: if !self.js_session_key_id.is_empty() { join_server_context: if !self.js_session_key_id.is_empty() {
Some(integration_pb::JoinServerContext { Some(common::JoinServerContext {
app_s_key: None, app_s_key: None,
session_key_id: self.js_session_key_id.clone(), session_key_id: self.js_session_key_id.clone(),
}) })
@ -695,7 +697,7 @@ impl JoinRequest {
if app_s_key.kek_label.is_empty() { if app_s_key.kek_label.is_empty() {
None None
} else { } else {
Some(integration_pb::JoinServerContext { Some(common::JoinServerContext {
app_s_key: Some(common::KeyEnvelope { app_s_key: Some(common::KeyEnvelope {
kek_label: app_s_key.kek_label.clone(), kek_label: app_s_key.kek_label.clone(),
aes_key: app_s_key.aes_key.clone(), aes_key: app_s_key.aes_key.clone(),
@ -714,7 +716,9 @@ impl JoinRequest {
fn set_pr_start_ans_payload(&mut self) -> Result<()> { fn set_pr_start_ans_payload(&mut self) -> Result<()> {
trace!("Setting PRStartAnsPayload"); trace!("Setting PRStartAnsPayload");
let ds = self.device_session.as_ref().unwrap(); let d = self.device.as_ref().unwrap();
let ds = d.get_device_session()?;
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?; let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let sender_id = NetID::from_slice(&self.pr_start_req.base.sender_id)?; let sender_id = NetID::from_slice(&self.pr_start_req.base.sender_id)?;
@ -753,8 +757,8 @@ impl JoinRequest {
.base .base
.to_base_payload_result(backend::ResultCode::Success, ""), .to_base_payload_result(backend::ResultCode::Success, ""),
phy_payload: self.join_accept.as_ref().unwrap().to_vec()?, phy_payload: self.join_accept.as_ref().unwrap().to_vec()?,
dev_eui: ds.dev_eui.clone(), dev_eui: d.dev_eui.to_vec(),
dev_addr: ds.dev_addr.clone(), dev_addr: d.get_dev_addr()?.to_vec(),
lifetime: if pr_lifetime.is_zero() { lifetime: if pr_lifetime.is_zero() {
None None
} else { } else {
@ -764,7 +768,7 @@ impl JoinRequest {
nwk_s_key, nwk_s_key,
f_cnt_up: Some(0), f_cnt_up: Some(0),
dl_meta_data: Some(backend::DLMetaData { dl_meta_data: Some(backend::DLMetaData {
dev_eui: ds.dev_eui.clone(), dev_eui: d.dev_eui.to_vec(),
dl_freq_1: Some(rx1_freq as f64 / 1_000_000.0), dl_freq_1: Some(rx1_freq as f64 / 1_000_000.0),
dl_freq_2: Some(rx2_freq as f64 / 1_000_000.0), dl_freq_2: Some(rx2_freq as f64 / 1_000_000.0),
rx_delay_1: Some(rx1_delay.as_secs() as usize), rx_delay_1: Some(rx1_delay.as_secs() as usize),

View File

@ -21,7 +21,7 @@ use crate::storage::{
device, device_profile, error::Error as StorageError, gateway, get_async_redis_conn, redis_key, device, device_profile, error::Error as StorageError, gateway, get_async_redis_conn, redis_key,
}; };
use crate::stream; use crate::stream;
use chirpstack_api::{common, gw, internal, stream as stream_pb}; use chirpstack_api::{common, gw, stream as stream_pb};
use lrwn::region::CommonName; use lrwn::region::CommonName;
use lrwn::{ForwardUplinkReq, MType, PhyPayload, EUI64}; use lrwn::{ForwardUplinkReq, MType, PhyPayload, EUI64};
@ -75,7 +75,6 @@ pub struct RelayContext {
pub req: ForwardUplinkReq, pub req: ForwardUplinkReq,
pub device: device::Device, pub device: device::Device,
pub device_profile: device_profile::DeviceProfile, pub device_profile: device_profile::DeviceProfile,
pub device_session: internal::DeviceSession,
pub must_ack: bool, pub must_ack: bool,
pub must_send_downlink: bool, pub must_send_downlink: bool,
} }
@ -169,8 +168,8 @@ async fn _deduplicate_uplink(event: gw::UplinkFrame) -> Result<()> {
None => "".to_string(), None => "".to_string(),
}; };
let key = redis_key(format!("up:collect:{}:{}", tx_info_str, phy_str)); let key = redis_key(format!("up:collect:{{{}:{}}}", tx_info_str, phy_str));
let lock_key = redis_key(format!("up:collect:{}:{}:lock", tx_info_str, phy_str)); let lock_key = redis_key(format!("up:collect:{{{}:{}}}:lock", tx_info_str, phy_str));
let dedup_delay = config::get().network.deduplication_delay; let dedup_delay = config::get().network.deduplication_delay;
let mut dedup_ttl = dedup_delay * 2; let mut dedup_ttl = dedup_delay * 2;
@ -180,15 +179,10 @@ async fn _deduplicate_uplink(event: gw::UplinkFrame) -> Result<()> {
trace!( trace!(
key = key.as_str(), key = key.as_str(),
"Adding uplink event to deduplication set" "Adding uplink event to deduplication set and getting lock"
); );
deduplicate_put(&key, dedup_ttl, &event).await?; let locked = deduplicate_put(&key, &lock_key, dedup_ttl, &event).await?;
if locked {
trace!(
lock_key = lock_key.as_str(),
"Requesting deduplication lock"
);
if deduplicate_locked(&lock_key, dedup_ttl).await? {
trace!( trace!(
lock_key = lock_key.as_str(), lock_key = lock_key.as_str(),
"Deduplication is already locked by an other process" "Deduplication is already locked by an other process"
@ -219,38 +213,36 @@ async fn _deduplicate_uplink(event: gw::UplinkFrame) -> Result<()> {
Ok(()) Ok(())
} }
async fn deduplicate_put(key: &str, ttl: Duration, event: &gw::UplinkFrame) -> Result<()> { async fn deduplicate_put(
collect_key: &str,
lock_key: &str,
ttl: Duration,
event: &gw::UplinkFrame,
) -> Result<bool> {
let event_b = event.encode_to_vec(); let event_b = event.encode_to_vec();
redis::pipe() let (lock_set,): (bool,) = redis::pipe()
.atomic() .atomic()
.cmd("SADD") .cmd("SADD")
.arg(key) .arg(collect_key)
.arg(event_b) .arg(event_b)
.ignore() .ignore()
.cmd("PEXPIRE") .cmd("PEXPIRE")
.arg(key) .arg(collect_key)
.arg(ttl.as_millis() as usize) .arg(ttl.as_millis() as usize)
.ignore() .ignore()
.query_async(&mut get_async_redis_conn().await?) .cmd("SET")
.await .arg(lock_key)
.context("Deduplication put")?;
Ok(())
}
async fn deduplicate_locked(key: &str, ttl: Duration) -> Result<bool> {
let set: bool = redis::cmd("SET")
.arg(key)
.arg("lock") .arg("lock")
.arg("PX") .arg("PX")
.arg(ttl.as_millis() as usize) .arg(ttl.as_millis() as usize)
.arg("NX") .arg("NX")
.query_async(&mut get_async_redis_conn().await?) .query_async(&mut get_async_redis_conn().await?)
.await .await
.context("Deduplication locked")?; .context("Deduplication put and get lock")?;
Ok(!set) // We get true if we were able to set the lock, thus true == not yet locked.
Ok(!lock_set)
} }
async fn deduplicate_collect(key: &str) -> Result<gw::UplinkFrameSet> { async fn deduplicate_collect(key: &str) -> Result<gw::UplinkFrameSet> {

View File

@ -11,6 +11,7 @@ pkgs.mkShell {
pkgs.perl pkgs.perl
pkgs.cmake pkgs.cmake
pkgs.clang pkgs.clang
pkgs.postgresql # needed to build the diesel cli utility
]; ];
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
BINDGEN_EXTRA_CLANG_ARGS = "-I${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.libclang.version}/include"; BINDGEN_EXTRA_CLANG_ARGS = "-I${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.libclang.version}/include";

View File

@ -5192,9 +5192,9 @@ flatted@^3.2.9:
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
follow-redirects@^1.0.0: follow-redirects@^1.0.0:
version "1.15.3" version "1.15.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
for-each@^0.3.3: for-each@^0.3.3:
version "0.3.3" version "0.3.3"