diff --git a/.golangci.yml b/.golangci.yml
index cbd0fc46f8..445e35f88e 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,7 +1,3 @@
-run:
- skip-dirs:
- - node_modules
-
linters:
disable-all: true
enable:
@@ -113,3 +109,6 @@ issues:
- linters:
- paralleltest
text: 'does not use range value in test Run'
+ exclude-dirs:
+ - node_modules
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6655089a04..819f6757eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,11 +14,21 @@ For details about compatibility between different releases, see the **Commitment
- Add recvTime field to the decodeUplink input in payload formatters
- Add the latest battery percentage of the end device in the `ApplicationUplink` message.
- Add live data split view tutorial to the Console.
+- Add end device attributes to ApplicationUp messages.
+ - Add the locations, version_ids, network_ids fields to the following ApplicationUp messages:
+ - ApplicationJoinAccept
+ - ApplicationDownlink
+ - ApplicationDownlinkFailed
+ - ApplicationInvalidatedDownlinks
+ - ApplicationServiceData
+ - Add Timeout and Cache fields in the EndDeviceMetadataStorageConfig of the AS.
### Changed
### Deprecated
+- Deprecate the Location field (and its subfields) in the EndDeviceMetadataStorageConfig of AS.
+
### Removed
### Fixed
diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md
index 1ee06e0ed6..568fcc96e0 100644
--- a/api/ttn/lorawan/v3/api.md
+++ b/api/ttn/lorawan/v3/api.md
@@ -596,19 +596,31 @@
- [Enum `TxSchedulePriority`](#ttn.lorawan.v3.TxSchedulePriority)
- [File `ttn/lorawan/v3/messages.proto`](#ttn/lorawan/v3/messages.proto)
- [Message `ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink)
+ - [Message `ApplicationDownlink.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlink.AttributesEntry)
- [Message `ApplicationDownlink.ClassBC`](#ttn.lorawan.v3.ApplicationDownlink.ClassBC)
- [Message `ApplicationDownlink.ConfirmedRetry`](#ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry)
+ - [Message `ApplicationDownlink.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlink.LocationsEntry)
- [Message `ApplicationDownlinkFailed`](#ttn.lorawan.v3.ApplicationDownlinkFailed)
+ - [Message `ApplicationDownlinkFailed.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry)
+ - [Message `ApplicationDownlinkFailed.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry)
- [Message `ApplicationDownlinks`](#ttn.lorawan.v3.ApplicationDownlinks)
- [Message `ApplicationInvalidatedDownlinks`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks)
+ - [Message `ApplicationInvalidatedDownlinks.AttributesEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry)
+ - [Message `ApplicationInvalidatedDownlinks.LocationsEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry)
- [Message `ApplicationJoinAccept`](#ttn.lorawan.v3.ApplicationJoinAccept)
+ - [Message `ApplicationJoinAccept.AttributesEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry)
+ - [Message `ApplicationJoinAccept.LocationsEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry)
- [Message `ApplicationLocation`](#ttn.lorawan.v3.ApplicationLocation)
- [Message `ApplicationLocation.AttributesEntry`](#ttn.lorawan.v3.ApplicationLocation.AttributesEntry)
- [Message `ApplicationServiceData`](#ttn.lorawan.v3.ApplicationServiceData)
+ - [Message `ApplicationServiceData.AttributesEntry`](#ttn.lorawan.v3.ApplicationServiceData.AttributesEntry)
+ - [Message `ApplicationServiceData.LocationsEntry`](#ttn.lorawan.v3.ApplicationServiceData.LocationsEntry)
- [Message `ApplicationUp`](#ttn.lorawan.v3.ApplicationUp)
- [Message `ApplicationUplink`](#ttn.lorawan.v3.ApplicationUplink)
+ - [Message `ApplicationUplink.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplink.AttributesEntry)
- [Message `ApplicationUplink.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplink.LocationsEntry)
- [Message `ApplicationUplinkNormalized`](#ttn.lorawan.v3.ApplicationUplinkNormalized)
+ - [Message `ApplicationUplinkNormalized.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry)
- [Message `ApplicationUplinkNormalized.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry)
- [Message `DownlinkMessage`](#ttn.lorawan.v3.DownlinkMessage)
- [Message `DownlinkQueueOperationErrorDetails`](#ttn.lorawan.v3.DownlinkQueueOperationErrorDetails)
@@ -8633,6 +8645,10 @@ Transmission settings for downlink.
| `priority` | [`TxSchedulePriority`](#ttn.lorawan.v3.TxSchedulePriority) | | Priority for scheduling the downlink message. |
| `correlation_ids` | [`string`](#string) | repeated | |
| `confirmed_retry` | [`ApplicationDownlink.ConfirmedRetry`](#ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry) | | |
+| `locations` | [`ApplicationDownlink.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlink.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
+| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
+| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationDownlink.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlink.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
@@ -8643,6 +8659,14 @@ Transmission settings for downlink.
| `frm_payload` |
`bytes.max_len`: `255`
|
| `priority` | `enum.defined_only`: `true`
|
| `correlation_ids` | `repeated.items.string.max_len`: `100`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationDownlink.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
### Message `ApplicationDownlink.ClassBC`
@@ -8664,12 +8688,23 @@ Transmission settings for downlink.
| ----- | ----------- |
| `max_attempts` | `uint32.lte`: `100`
`uint32.gt`: `0`
|
+### Message `ApplicationDownlink.LocationsEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`Location`](#ttn.lorawan.v3.Location) | | |
+
### Message `ApplicationDownlinkFailed`
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `downlink` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | | |
| `error` | [`ErrorDetails`](#ttn.lorawan.v3.ErrorDetails) | | |
+| `locations` | [`ApplicationDownlinkFailed.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
+| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
+| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationDownlinkFailed.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
@@ -8677,6 +8712,21 @@ Transmission settings for downlink.
| ----- | ----------- |
| `downlink` | `message.required`: `true`
|
| `error` | `message.required`: `true`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationDownlinkFailed.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
+
+### Message `ApplicationDownlinkFailed.LocationsEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`Location`](#ttn.lorawan.v3.Location) | | |
### Message `ApplicationDownlinks`
@@ -8691,12 +8741,31 @@ Transmission settings for downlink.
| `downlinks` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | repeated | |
| `last_f_cnt_down` | [`uint32`](#uint32) | | |
| `session_key_id` | [`bytes`](#bytes) | | |
+| `locations` | [`ApplicationInvalidatedDownlinks.LocationsEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
+| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
+| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationInvalidatedDownlinks.AttributesEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
| Field | Validations |
| ----- | ----------- |
| `session_key_id` | `bytes.max_len`: `2048`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationInvalidatedDownlinks.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
+
+### Message `ApplicationInvalidatedDownlinks.LocationsEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`Location`](#ttn.lorawan.v3.Location) | | |
### Message `ApplicationJoinAccept`
@@ -8707,6 +8776,10 @@ Transmission settings for downlink.
| `invalidated_downlinks` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | repeated | Downlink messages in the queue that got invalidated because of the session change. |
| `pending_session` | [`bool`](#bool) | | Indicates whether the security context refers to the pending session, i.e. when this join-accept is an answer to a rejoin-request. |
| `received_at` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | Server time when the Network Server received the message. |
+| `locations` | [`ApplicationJoinAccept.LocationsEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
+| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
+| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationJoinAccept.AttributesEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
@@ -8714,6 +8787,21 @@ Transmission settings for downlink.
| ----- | ----------- |
| `session_key_id` | `bytes.max_len`: `2048`
|
| `received_at` | `timestamp.required`: `true`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationJoinAccept.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
+
+### Message `ApplicationJoinAccept.LocationsEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`Location`](#ttn.lorawan.v3.Location) | | |
### Message `ApplicationLocation`
@@ -8743,6 +8831,30 @@ Transmission settings for downlink.
| ----- | ---- | ----- | ----------- |
| `service` | [`string`](#string) | | |
| `data` | [`google.protobuf.Struct`](#google.protobuf.Struct) | | |
+| `locations` | [`ApplicationServiceData.LocationsEntry`](#ttn.lorawan.v3.ApplicationServiceData.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
+| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
+| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationServiceData.AttributesEntry`](#ttn.lorawan.v3.ApplicationServiceData.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
+
+#### Field Rules
+
+| Field | Validations |
+| ----- | ----------- |
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationServiceData.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
+
+### Message `ApplicationServiceData.LocationsEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`Location`](#ttn.lorawan.v3.Location) | | |
### Message `ApplicationUp`
@@ -8797,6 +8909,7 @@ Application uplink message.
| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
| `last_battery_percentage` | [`LastBatteryPercentage`](#ttn.lorawan.v3.LastBatteryPercentage) | | Last battery percentage of the end device. Received via the DevStatus MAC command at last_dev_status_received_at or earlier. Set by the Network Server while handling the message. |
+| `attributes` | [`ApplicationUplink.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplink.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
@@ -8805,6 +8918,14 @@ Application uplink message.
| `session_key_id` | `bytes.max_len`: `2048`
|
| `f_port` | `uint32.lte`: `255`
`uint32.not_in`: `[224]`
|
| `settings` | `message.required`: `true`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationUplink.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
### Message `ApplicationUplink.LocationsEntry`
@@ -8831,6 +8952,7 @@ Application uplink message.
| `locations` | [`ApplicationUplinkNormalized.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. |
| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. |
| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. |
+| `attributes` | [`ApplicationUplinkNormalized.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. |
#### Field Rules
@@ -8841,6 +8963,14 @@ Application uplink message.
| `normalized_payload` | `message.required`: `true`
|
| `settings` | `message.required`: `true`
|
| `received_at` | `timestamp.required`: `true`
|
+| `attributes` | `map.max_pairs`: `10`
`map.keys.string.max_len`: `36`
`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`
`map.values.string.max_len`: `200`
|
+
+### Message `ApplicationUplinkNormalized.AttributesEntry`
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `key` | [`string`](#string) | | |
+| `value` | [`string`](#string) | | |
### Message `ApplicationUplinkNormalized.LocationsEntry`
diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json
index 57c7d5b5ce..626f161912 100644
--- a/api/ttn/lorawan/v3/api.swagger.json
+++ b/api/ttn/lorawan/v3/api.swagger.json
@@ -20326,6 +20326,28 @@
},
"confirmed_retry": {
"$ref": "#/definitions/ApplicationDownlinkConfirmedRetry"
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/lorawanv3Location"
+ },
+ "description": "End device location metadata, set by the Application Server while handling the message."
+ },
+ "version_ids": {
+ "$ref": "#/definitions/v3EndDeviceVersionIdentifiers",
+ "description": "End device version identifiers, set by the Application Server while handling the message."
+ },
+ "network_ids": {
+ "$ref": "#/definitions/v3NetworkIdentifiers",
+ "description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -20337,6 +20359,28 @@
},
"error": {
"$ref": "#/definitions/v3ErrorDetails"
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/lorawanv3Location"
+ },
+ "description": "End device location metadata, set by the Application Server while handling the message."
+ },
+ "version_ids": {
+ "$ref": "#/definitions/v3EndDeviceVersionIdentifiers",
+ "description": "End device version identifiers, set by the Application Server while handling the message."
+ },
+ "network_ids": {
+ "$ref": "#/definitions/v3NetworkIdentifiers",
+ "description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -20377,6 +20421,28 @@
"session_key_id": {
"type": "string",
"format": "byte"
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/lorawanv3Location"
+ },
+ "description": "End device location metadata, set by the Application Server while handling the message."
+ },
+ "version_ids": {
+ "$ref": "#/definitions/v3EndDeviceVersionIdentifiers",
+ "description": "End device version identifiers, set by the Application Server while handling the message."
+ },
+ "network_ids": {
+ "$ref": "#/definitions/v3NetworkIdentifiers",
+ "description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -20408,6 +20474,28 @@
"type": "string",
"format": "date-time",
"description": "Server time when the Network Server received the message."
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/lorawanv3Location"
+ },
+ "description": "End device location metadata, set by the Application Server while handling the message."
+ },
+ "version_ids": {
+ "$ref": "#/definitions/v3EndDeviceVersionIdentifiers",
+ "description": "End device version identifiers, set by the Application Server while handling the message."
+ },
+ "network_ids": {
+ "$ref": "#/definitions/v3NetworkIdentifiers",
+ "description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -20907,6 +20995,28 @@
},
"data": {
"type": "object"
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/lorawanv3Location"
+ },
+ "description": "End device location metadata, set by the Application Server while handling the message."
+ },
+ "version_ids": {
+ "$ref": "#/definitions/v3EndDeviceVersionIdentifiers",
+ "description": "End device version identifiers, set by the Application Server while handling the message."
+ },
+ "network_ids": {
+ "$ref": "#/definitions/v3NetworkIdentifiers",
+ "description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -21072,6 +21182,13 @@
"last_battery_percentage": {
"$ref": "#/definitions/v3LastBatteryPercentage",
"description": "Last battery percentage of the end device.\nReceived via the DevStatus MAC command at last_dev_status_received_at or earlier.\nSet by the Network Server while handling the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
@@ -21148,6 +21265,13 @@
"network_ids": {
"$ref": "#/definitions/v3NetworkIdentifiers",
"description": "Network identifiers, set by the Network Server that handles the message."
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Attributes for devices, set by the Application Server while handling the message."
}
}
},
diff --git a/api/ttn/lorawan/v3/messages.proto b/api/ttn/lorawan/v3/messages.proto
index 84b69891d3..0d09cff9ee 100644
--- a/api/ttn/lorawan/v3/messages.proto
+++ b/api/ttn/lorawan/v3/messages.proto
@@ -277,7 +277,21 @@ message ApplicationUplink {
// Set by the Network Server while handling the message.
LastBatteryPercentage last_battery_percentage = 20;
- // next: 21
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 21 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 22
}
message ApplicationUplinkNormalized {
@@ -330,7 +344,21 @@ message ApplicationUplinkNormalized {
// Network identifiers, set by the Network Server that handles the message.
NetworkIdentifiers network_ids = 14;
- // next: 15
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 15 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 16
}
message ApplicationLocation {
@@ -370,6 +398,31 @@ message ApplicationJoinAccept {
bool pending_session = 4;
// Server time when the Network Server received the message.
google.protobuf.Timestamp received_at = 8 [(validate.rules).timestamp.required = true];
+
+ // End device location metadata, set by the Application Server while handling the message.
+ map locations = 9;
+
+ // End device version identifiers, set by the Application Server while handling the message.
+ EndDeviceVersionIdentifiers version_ids = 10;
+
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIdentifiers network_ids = 11;
+
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 12 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 13
}
message ApplicationDownlink {
@@ -456,7 +509,30 @@ message ApplicationDownlink {
ConfirmedRetry confirmed_retry = 11;
- // next: 12
+ // End device location metadata, set by the Application Server while handling the message.
+ map locations = 12;
+
+ // End device version identifiers, set by the Application Server while handling the message.
+ EndDeviceVersionIdentifiers version_ids = 13;
+
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIdentifiers network_ids = 14;
+
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 15 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 16
}
message ApplicationDownlinks {
@@ -470,6 +546,31 @@ message ApplicationDownlinkFailed {
};
ApplicationDownlink downlink = 1 [(validate.rules).message.required = true];
ErrorDetails error = 2 [(validate.rules).message.required = true];
+
+ // End device location metadata, set by the Application Server while handling the message.
+ map locations = 3;
+
+ // End device version identifiers, set by the Application Server while handling the message.
+ EndDeviceVersionIdentifiers version_ids = 4;
+
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIdentifiers network_ids = 5;
+
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 6 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 7
}
message ApplicationInvalidatedDownlinks {
@@ -480,6 +581,31 @@ message ApplicationInvalidatedDownlinks {
repeated ApplicationDownlink downlinks = 1;
uint32 last_f_cnt_down = 2;
bytes session_key_id = 3 [(validate.rules).bytes.max_len = 2048];
+
+ // End device location metadata, set by the Application Server while handling the message.
+ map locations = 4;
+
+ // End device version identifiers, set by the Application Server while handling the message.
+ EndDeviceVersionIdentifiers version_ids = 5;
+
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIdentifiers network_ids = 6;
+
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 7 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 8
}
message DownlinkQueueOperationErrorDetails {
@@ -527,6 +653,31 @@ message ApplicationServiceData {
};
string service = 1;
google.protobuf.Struct data = 2;
+
+ // End device location metadata, set by the Application Server while handling the message.
+ map locations = 3;
+
+ // End device version identifiers, set by the Application Server while handling the message.
+ EndDeviceVersionIdentifiers version_ids = 4;
+
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIdentifiers network_ids = 5;
+
+ // Attributes for devices, set by the Application Server while handling the message.
+ map attributes = 6 [(validate.rules).map = {
+ max_pairs: 10,
+ keys: {
+ string: {
+ pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$",
+ max_len: 36
+ }
+ },
+ values: {
+ string: {max_len: 200}
+ }
+ }];
+
+ // next: 7
}
// Application uplink message.
diff --git a/cmd/internal/shared/applicationserver/config.go b/cmd/internal/shared/applicationserver/config.go
index 0a680a3819..b420608610 100644
--- a/cmd/internal/shared/applicationserver/config.go
+++ b/cmd/internal/shared/applicationserver/config.go
@@ -49,15 +49,7 @@ var DefaultApplicationServerConfig = applicationserver.Config{
Downlinks: web.DownlinksConfig{PublicAddress: shared.DefaultPublicURL + "/api/v3"},
},
EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{
- Location: applicationserver.EndDeviceLocationStorageConfig{
- Timeout: 5 * time.Second,
- Cache: applicationserver.EndDeviceLocationStorageCacheConfig{
- Enable: true,
- MinRefreshInterval: 15 * time.Minute,
- MaxRefreshInterval: 4 * time.Hour,
- TTL: 14 * 24 * time.Hour,
- },
- },
+ Timeout: 5 * time.Second,
},
Distribution: applicationserver.DistributionConfig{
Timeout: time.Minute,
diff --git a/cmd/ttn-lw-stack/commands/start.go b/cmd/ttn-lw-stack/commands/start.go
index ec3eaf7b09..8a8820fd31 100644
--- a/cmd/ttn-lw-stack/commands/start.go
+++ b/cmd/ttn-lw-stack/commands/start.go
@@ -27,7 +27,6 @@ import (
asioapredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/packages/redis"
asiopsredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/pubsub/redis"
asiowebredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/web/redis"
- asmetaredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis"
asredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/redis"
"go.thethings.network/lorawan-stack/v3/pkg/component"
"go.thethings.network/lorawan-stack/v3/pkg/console"
@@ -445,21 +444,11 @@ var startCommand = &cobra.Command{
}
config.AS.Webhooks.Registry = webhookRegistry
}
- if cache := &config.AS.EndDeviceMetadataStorage.Location.Cache; cache.Enable {
- switch config.Cache.Service {
- case "redis":
- cache.Cache = &asmetaredis.EndDeviceLocationCache{
- Redis: redis.New(config.Cache.Redis.WithNamespace("as", "metadata", "locations")),
- }
- default:
- cache.Enable = false
- }
- }
- locationRegistry, err := config.AS.EndDeviceMetadataStorage.Location.NewRegistry(ctx, c)
+ endDeviceRegistry, err := config.AS.EndDeviceMetadataStorage.NewRegistry(ctx, c)
if err != nil {
return shared.ErrInitializeApplicationServer.WithCause(err)
}
- config.AS.EndDeviceMetadataStorage.Location.Registry = locationRegistry
+ config.AS.EndDeviceMetadataStorage.Registry = endDeviceRegistry
as, err := applicationserver.New(c, &config.AS)
if err != nil {
return shared.ErrInitializeApplicationServer.WithCause(err)
diff --git a/config/messages.json b/config/messages.json
index a474d02dbf..5109030ed5 100644
--- a/config/messages.json
+++ b/config/messages.json
@@ -2861,13 +2861,13 @@
"file": "io.go"
}
},
- "error:pkg/applicationserver/metadata/redis:cache_miss": {
+ "error:pkg/applicationserver/metadata:field_mask_path_not_supported": {
"translations": {
- "en": "cache miss"
+ "en": "field mask path `{path}` is not supported"
},
"description": {
- "package": "pkg/applicationserver/metadata/redis",
- "file": "location_cache.go"
+ "package": "pkg/applicationserver/metadata",
+ "file": "metadata.go"
}
},
"error:pkg/applicationserver/redis:application_uid": {
@@ -2978,15 +2978,6 @@
"file": "config.go"
}
},
- "error:pkg/applicationserver:invalid_ttl": {
- "translations": {
- "en": "invalid TTL `{ttl}`"
- },
- "description": {
- "package": "pkg/applicationserver",
- "file": "config.go"
- }
- },
"error:pkg/applicationserver:join_server_unavailable": {
"translations": {
"en": "Join Server unavailable for JoinEUI `{join_eui}`"
diff --git a/pkg/applicationserver/applicationserver.go b/pkg/applicationserver/applicationserver.go
index 1559c1736f..48aeeb306c 100644
--- a/pkg/applicationserver/applicationserver.go
+++ b/pkg/applicationserver/applicationserver.go
@@ -81,7 +81,7 @@ type ApplicationServer struct {
linkRegistry LinkRegistry
deviceRegistry DeviceRegistry
- locationRegistry metadata.EndDeviceLocationRegistry
+ endDeviceRegistry metadata.EndDeviceRegistry
formatters messageprocessors.MapPayloadProcessor
webhooks ioweb.Webhooks
webhookTemplates ioweb.TemplateStore
@@ -156,14 +156,14 @@ func New(c *component.Component, conf *Config) (as *ApplicationServer, err error
}
as = &ApplicationServer{
- Component: c,
- ctx: ctx,
- config: conf,
- linkRegistry: conf.Links,
- deviceRegistry: wrapEndDeviceRegistryWithReplacedFields(conf.Devices, replacedEndDeviceFields...),
- appPkgRegistry: conf.Packages.Registry,
- locationRegistry: conf.EndDeviceMetadataStorage.Location.Registry,
- formatters: make(messageprocessors.MapPayloadProcessor),
+ Component: c,
+ ctx: ctx,
+ config: conf,
+ linkRegistry: conf.Links,
+ deviceRegistry: wrapEndDeviceRegistryWithReplacedFields(conf.Devices, replacedEndDeviceFields...),
+ appPkgRegistry: conf.Packages.Registry,
+ endDeviceRegistry: conf.EndDeviceMetadataStorage.Registry,
+ formatters: make(messageprocessors.MapPayloadProcessor),
clusterDistributor: distribution.NewPubSubDistributor(
ctx,
c,
@@ -1049,6 +1049,14 @@ func (as *ApplicationServer) handleJoinAccept(
return err
}
+ if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve end device attributes on join-accept",
+ )
+ } else {
+ joinAccept.Attributes = entity.Attributes
+ }
+
// Publish last seen event.
if err := as.deviceLastSeenPool.Publish(ctx, lastSeenAtInfo{
ids: ids,
@@ -1159,6 +1167,7 @@ func (as *ApplicationServer) publishNormalizedUplink(ctx context.Context, info u
Locations: info.uplink.Locations,
VersionIds: info.uplink.VersionIds,
NetworkIds: info.uplink.NetworkIds,
+ Attributes: info.uplink.Attributes,
},
},
Simulated: info.simulated,
@@ -1208,6 +1217,15 @@ func (as *ApplicationServer) handleUplink(ctx context.Context, info uplinkInfo)
return err
}
+ if entity, err := as.endDeviceRegistry.Get(ctx, info.ids, []string{"attributes", "locations"}); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve the end device attributes and locations on uplink",
+ )
+ } else {
+ info.uplink.Attributes = entity.Attributes
+ info.uplink.Locations = entity.Locations
+ }
+
if !as.skipPayloadCrypto(ctx, info.link, dev, dev.Session) {
if err := as.decryptAndDecodeUplink(ctx, dev, info.uplink, info.link.DefaultFormatters); err != nil {
return err
@@ -1227,11 +1245,6 @@ func (as *ApplicationServer) handleUplink(ctx context.Context, info uplinkInfo)
}
// Set location in message and publish location solved if the payload contains location information.
- if locations, err := as.locationRegistry.Get(ctx, info.ids); err != nil {
- log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations")
- } else {
- info.uplink.Locations = locations
- }
loc := as.locationFromPayload(info.uplink)
if loc != nil {
if info.uplink.Locations == nil {
@@ -1285,10 +1298,14 @@ func (as *ApplicationServer) handleSimulatedUplink(ctx context.Context, info upl
return err
}
- if locations, err := as.locationRegistry.Get(ctx, info.ids); err != nil {
- log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations")
+ if entity, err := as.endDeviceRegistry.Get(ctx, info.ids, []string{"attributes", "locations"}); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve the end device from entity registry on simulated uplink",
+ )
} else {
- info.uplink.Locations = locations
+ info.uplink.Attributes = entity.Attributes
+ info.uplink.Locations = entity.Locations
+
}
if err := as.decodeUplink(ctx, dev, info.uplink, info.link.DefaultFormatters); err != nil {
@@ -1370,7 +1387,19 @@ func (as *ApplicationServer) handleDownlinkQueueInvalidated(
return dev, mask, nil
},
)
- return pass, err
+ if err != nil {
+ return pass, err
+ }
+
+ if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve end device attributes on downlink queue invalidated",
+ )
+ } else {
+ invalid.Attributes = entity.Attributes
+ }
+
+ return pass, nil
}
func (as *ApplicationServer) handleDownlinkNack(
@@ -1455,17 +1484,47 @@ func (as *ApplicationServer) handleDownlinkNack(
return dev, mask, nil
},
)
- return err
+ if err != nil {
+ return err
+ }
+
+ if _, err = as.endDeviceRegistry.Set(ctx, ids, []string{"attributes"},
+ func(entity *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) {
+ if entity == nil {
+ return nil, nil, errDeviceNotFound.WithAttributes("device_uid", unique.ID(ctx, ids))
+ }
+ msg.Attributes = entity.Attributes
+ return entity, []string{""}, nil
+ },
+ ); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve end device attributes on downlink nack",
+ )
+ }
+
+ return nil
}
-// handleLocationSolved saves the provided *ttnpb.ApplicationLocation in the Entity Registry as part of the device locations.
-// Locations provided by other services will be maintained.
+// handleLocationSolved saves the provided *ttnpb.ApplicationLocation in the Entity Registry as part of the device
+// locations. Locations provided by other services will be maintained.
func (as *ApplicationServer) handleLocationSolved(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, msg *ttnpb.ApplicationLocation, link *ttnpb.ApplicationLink) error {
defer trace.StartRegion(ctx, "handle location solved").End()
- if _, err := as.locationRegistry.Merge(ctx, ids, map[string]*ttnpb.Location{
- msg.Service: msg.Location,
- }); err != nil {
+ if _, err := as.endDeviceRegistry.Set(ctx, ids, []string{"locations"},
+ func(stored *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) {
+ if stored == nil {
+ return nil, nil, errDeviceNotFound.WithAttributes("device_uid", unique.ID(ctx, ids))
+ }
+
+ if len(stored.Locations) == 0 {
+ stored.Locations = make(map[string]*ttnpb.Location)
+ }
+
+ stored.Locations[msg.Service] = msg.Location
+
+ return stored, []string{"locations"}, nil
+ },
+ ); err != nil {
log.FromContext(ctx).WithError(err).Warn("Failed to merge end device locations")
}
return nil
@@ -1486,6 +1545,15 @@ func (as *ApplicationServer) decryptDownlinkMessage(ctx context.Context, ids *tt
if err != nil {
return err
}
+
+ if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil {
+ log.FromContext(ctx).WithError(err).Warn(
+ "Failed to retrieve end device attributes on downlink message",
+ )
+ } else {
+ msg.Attributes = entity.Attributes
+ }
+
var session *ttnpb.Session
switch {
case dev.Session != nil && bytes.Equal(dev.Session.Keys.SessionKeyId, msg.SessionKeyId):
diff --git a/pkg/applicationserver/applicationserver_test.go b/pkg/applicationserver/applicationserver_test.go
index 0c37b39110..ce5999de30 100644
--- a/pkg/applicationserver/applicationserver_test.go
+++ b/pkg/applicationserver/applicationserver_test.go
@@ -303,9 +303,7 @@ func TestApplicationServer(t *testing.T) {
},
},
EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{
- Location: applicationserver.EndDeviceLocationStorageConfig{
- Registry: metadata.NewNoopEndDeviceLocationRegistry(),
- },
+ Registry: metadata.NewNoopEndDeviceRegistry(),
},
Downlinks: applicationserver.DownlinksConfig{
ConfirmationConfig: applicationserver.ConfirmationConfig{
@@ -2414,9 +2412,7 @@ func TestSkipPayloadCrypto(t *testing.T) {
},
},
EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{
- Location: applicationserver.EndDeviceLocationStorageConfig{
- Registry: metadata.NewNoopEndDeviceLocationRegistry(),
- },
+ Registry: metadata.NewNoopEndDeviceRegistry(),
},
Downlinks: applicationserver.DownlinksConfig{
ConfirmationConfig: applicationserver.ConfirmationConfig{
@@ -2916,9 +2912,7 @@ func TestLocationFromPayload(t *testing.T) {
},
},
EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{
- Location: applicationserver.EndDeviceLocationStorageConfig{
- Registry: metadata.NewClusterEndDeviceLocationRegistry(c, (1<<4)*Timeout),
- },
+ Registry: metadata.NewClusterEndDeviceRegistry(c, (1<<4)*Timeout),
},
Downlinks: applicationserver.DownlinksConfig{
ConfirmationConfig: applicationserver.ConfirmationConfig{
@@ -3101,9 +3095,7 @@ func TestUplinkNormalized(t *testing.T) {
},
},
EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{
- Location: applicationserver.EndDeviceLocationStorageConfig{
- Registry: metadata.NewClusterEndDeviceLocationRegistry(c, (1<<4)*Timeout),
- },
+ Registry: metadata.NewClusterEndDeviceRegistry(c, (1<<4)*Timeout),
},
Downlinks: applicationserver.DownlinksConfig{
ConfirmationConfig: applicationserver.ConfirmationConfig{
diff --git a/pkg/applicationserver/config.go b/pkg/applicationserver/config.go
index 54b46ca378..d9b69272fa 100644
--- a/pkg/applicationserver/config.go
+++ b/pkg/applicationserver/config.go
@@ -49,9 +49,9 @@ type InteropConfig struct {
// EndDeviceFetcherConfig represents configuration for the end device fetcher in Application Server.
type EndDeviceFetcherConfig struct {
- Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"`
- Cache EndDeviceFetcherCacheConfig `name:"cache" description:"Cache configuration options for the end device fetcher"`
- CircuitBreaker EndDeviceFetcherCircuitBreakerConfig `name:"circuit-breaker" description:"Circuit breaker options for the end device fetcher"`
+ Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"` // nolint:lll
+ Cache EndDeviceFetcherCacheConfig `name:"cache" description:"Cache configuration options for the end device fetcher"` // nolint:lll
+ CircuitBreaker EndDeviceFetcherCircuitBreakerConfig `name:"circuit-breaker" description:"Circuit breaker options for the end device fetcher"` // nolint:lll
}
// EndDeviceFetcherCacheConfig represents configuration for device information caching in Application Server.
@@ -65,33 +65,37 @@ type EndDeviceFetcherCacheConfig struct {
type EndDeviceFetcherCircuitBreakerConfig struct {
Enable bool `name:"enable" description:"Enable circuit breaker behavior on burst errors"`
Timeout time.Duration `name:"timeout" description:"Timeout after which the circuit breaker closes"`
- Threshold int `name:"threshold" description:"Number of failed fetching attempts after which the circuit breaker opens"`
+ Threshold int `name:"threshold" description:"Number of failed fetching attempts after which the circuit breaker opens"` // nolint:lll
}
// EndDeviceMetadataStorageConfig represents the configuration of end device metadata operations.
type EndDeviceMetadataStorageConfig struct {
- Location EndDeviceLocationStorageConfig `name:"location"`
+ // DEPRECATED: use the EndDeviceRegistry for location storage.
+ Location EndDeviceLocationStorageConfig `name:"location" description:"DEPRECATED setting."`
+
+ Registry metadata.EndDeviceRegistry `name:"-"`
+ Timeout time.Duration `name:"timeout" description:"Timeout of the entity registry retrieval operation"` // nolint:lll
}
// EndDeviceLocationStorageConfig represents the configuration of end device locations storage.
+// DEPRECATED: use the metadata.EndDeviceRegistry for location storage.
type EndDeviceLocationStorageConfig struct {
- Registry metadata.EndDeviceLocationRegistry `name:"-"`
- Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"`
- Cache EndDeviceLocationStorageCacheConfig `name:"cache"`
+ Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrieval operation. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
+ Cache EndDeviceLocationStorageCacheConfig `name:"cache" description:"DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
}
// EndDeviceLocationStorageCacheConfig represents the configuration of end device location registry caching.
+// DEPRECATED: use the metadata.EndDeviceRegistryCache and the locations field of end devices for caching.
type EndDeviceLocationStorageCacheConfig struct {
- Cache metadata.EndDeviceLocationCache `name:"-"`
- Enable bool `name:"enable" description:"Enable caching of end device locations"`
- MinRefreshInterval time.Duration `name:"min-refresh-interval" description:"Minimum time interval between two asynchronous refreshes"`
- MaxRefreshInterval time.Duration `name:"max-refresh-interval" description:"Maximum time interval between two asynchronous refreshes"`
- TTL time.Duration `name:"eviction-ttl" description:"Time to live of cached locations"`
+ Enable bool `name:"enable" description:"Enable caching of end device locations. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
+ MinRefreshInterval time.Duration `name:"min-refresh-interval" description:"Minimum time interval between two asynchronous refreshes. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
+ MaxRefreshInterval time.Duration `name:"max-refresh-interval" description:"Maximum time interval between two asynchronous refreshes. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
+ TTL time.Duration `name:"eviction-ttl" description:"Time to live of cached locations. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll
}
// FormattersConfig represents the configuration for payload formatters.
type FormattersConfig struct {
- MaxParameterLength int `name:"max-parameter-length" description:"Maximum allowed size for length of formatter parameters (payload formatter scripts)"`
+ MaxParameterLength int `name:"max-parameter-length" description:"Maximum allowed size for length of formatter parameters (payload formatter scripts)"` // nolint:lll
}
// ConfirmationConfig represents the configuration for confirmed downlink.
@@ -112,21 +116,21 @@ type PaginationConfig struct {
// Config represents the ApplicationServer configuration.
type Config struct {
- LinkMode string `name:"link-mode" description:"Deprecated - mode to link applications to their Network Server (all, explicit)"`
+ LinkMode string `name:"link-mode" description:"Deprecated - mode to link applications to their Network Server (all, explicit)"` // nolint:lll
Devices DeviceRegistry `name:"-"`
Links LinkRegistry `name:"-"`
UplinkStorage UplinkStorageConfig `name:"uplink-storage" description:"Application uplinks storage configuration"`
Formatters FormattersConfig `name:"formatters" description:"Payload formatters configuration"`
Distribution DistributionConfig `name:"distribution" description:"Distribution configuration"`
- EndDeviceFetcher EndDeviceFetcherConfig `name:"fetcher" description:"Deprecated - End Device fetcher configuration"`
- EndDeviceMetadataStorage EndDeviceMetadataStorageConfig `name:"end-device-metadata-storage" description:"End device metadata storage configuration"`
+ EndDeviceFetcher EndDeviceFetcherConfig `name:"fetcher" description:"Deprecated - End Device fetcher configuration"` // nolint:lll
+ EndDeviceMetadataStorage EndDeviceMetadataStorageConfig `name:"end-device-metadata-storage" description:"End device metadata storage configuration"` // nolint:lll
MQTT config.MQTT `name:"mqtt" description:"MQTT configuration"`
Webhooks WebhooksConfig `name:"webhooks" description:"Webhooks configuration"`
PubSub PubSubConfig `name:"pubsub" description:"Pub/sub messaging configuration"`
Packages ApplicationPackagesConfig `name:"packages" description:"Application packages configuration"`
Interop InteropConfig `name:"interop" description:"Interop client configuration"`
- DeviceKEKLabel string `name:"device-kek-label" description:"Label of KEK used to encrypt device keys at rest"`
- DeviceLastSeen LastSeenConfig `name:"device-last-seen" description:"End Device last seen batch update configuration"`
+ DeviceKEKLabel string `name:"device-kek-label" description:"Label of KEK used to encrypt device keys at rest"` // nolint:lll
+ DeviceLastSeen LastSeenConfig `name:"device-last-seen" description:"End Device last seen batch update configuration"` // nolint:lll
Downlinks DownlinksConfig `name:"downlinks" description:"Downlink configuration"`
Pagination PaginationConfig `name:"pagination" description:"Pagination configuration"`
}
@@ -153,10 +157,10 @@ type UplinkStorageConfig struct {
type WebhooksConfig struct {
Registry web.WebhookRegistry `name:"-"`
Target string `name:"target" description:"Target of the integration (direct)"`
- Timeout time.Duration `name:"timeout" description:"Wait timeout of the target to process the request"`
+ Timeout time.Duration `name:"timeout" description:"Wait timeout of the target to process the request"` // nolint:lll
QueueSize int `name:"queue-size" description:"Number of requests to queue"`
Workers int `name:"workers" description:"Number of workers to process requests"`
- UnhealthyAttemptsThreshold int `name:"unhealthy-attempts-threshold" description:"Number of failed webhook attempts before the webhook is disabled"`
+ UnhealthyAttemptsThreshold int `name:"unhealthy-attempts-threshold" description:"Number of failed webhook attempts before the webhook is disabled"` // nolint:lll
UnhealthyRetryInterval time.Duration `name:"unhealthy-retry-interval" description:"Time interval after which disabled webhooks may execute again"`
Templates web.TemplatesConfig `name:"templates" description:"The store of the webhook templates"`
Downlinks web.DownlinksConfig `name:"downlink" description:"The downlink queue operations configuration"`
@@ -292,7 +296,10 @@ func (c PubSubConfig) NewPubSub(comp *component.Component, server io.Server) (*p
// NewApplicationPackages returns a new applications packages frontend based on the configuration.
// If the registry is nil, it returns nil.
-func (c ApplicationPackagesConfig) NewApplicationPackages(ctx context.Context, server io.Server) (packages.Server, error) {
+func (c ApplicationPackagesConfig) NewApplicationPackages(
+ ctx context.Context,
+ server io.Server,
+) (packages.Server, error) {
if c.Registry == nil {
return nil, nil
}
@@ -310,27 +317,19 @@ func (c ApplicationPackagesConfig) NewApplicationPackages(ctx context.Context, s
return packages.New(ctx, server, c.Registry, handlers, c.Workers, c.Timeout)
}
-var (
- errInvalidTimeout = errors.DefineInvalidArgument("invalid_timeout", "invalid timeout `{timeout}`")
- errInvalidTTL = errors.DefineInvalidArgument("invalid_ttl", "invalid TTL `{ttl}`")
-)
+var errInvalidTimeout = errors.DefineInvalidArgument("invalid_timeout", "invalid timeout `{timeout}`")
-// NewRegistry returns a new end device location registry based on the configuration.
-func (c EndDeviceLocationStorageConfig) NewRegistry(ctx context.Context, comp *component.Component) (metadata.EndDeviceLocationRegistry, error) {
+// NewRegistry returns a new end device attributes registry based on the configuration.
+func (c EndDeviceMetadataStorageConfig) NewRegistry(
+ _ context.Context,
+ comp *component.Component,
+) (metadata.EndDeviceRegistry, error) {
if c.Timeout <= 0 {
return nil, errInvalidTimeout.WithAttributes("timeout", c.Timeout)
}
- registry := metadata.NewClusterEndDeviceLocationRegistry(comp, c.Timeout)
- registry = metadata.NewMetricsEndDeviceLocationRegistry(registry)
- if c.Cache.Enable {
- for _, ttl := range []time.Duration{c.Cache.MinRefreshInterval, c.Cache.MaxRefreshInterval, c.Cache.TTL} {
- if ttl <= 0 {
- return nil, errInvalidTTL.WithAttributes("ttl", ttl)
- }
- }
- cache := metadata.NewMetricsEndDeviceLocationCache(c.Cache.Cache)
- registry = metadata.NewCachedEndDeviceLocationRegistry(ctx, comp, registry, cache, c.Cache.MinRefreshInterval, c.Cache.MaxRefreshInterval, c.Cache.TTL)
- }
+ registry := metadata.NewClusterEndDeviceRegistry(comp, c.Timeout)
+ registry = metadata.NewMetricsEndDeviceRegistry(registry)
+
return registry, nil
}
diff --git a/pkg/applicationserver/metadata/cluster.go b/pkg/applicationserver/metadata/cluster.go
new file mode 100644
index 0000000000..63eee88360
--- /dev/null
+++ b/pkg/applicationserver/metadata/cluster.go
@@ -0,0 +1,29 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metadata
+
+import (
+ "context"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/cluster"
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+ "google.golang.org/grpc"
+)
+
+// ClusterPeerAccess provides access to cluster peers.
+type ClusterPeerAccess interface {
+ GetPeerConn(ctx context.Context, role ttnpb.ClusterRole, ids cluster.EntityIdentifiers) (*grpc.ClientConn, error)
+ WithClusterAuth() grpc.CallOption
+}
diff --git a/pkg/applicationserver/metadata/end_device_registry.go b/pkg/applicationserver/metadata/end_device_registry.go
new file mode 100644
index 0000000000..d133c811b4
--- /dev/null
+++ b/pkg/applicationserver/metadata/end_device_registry.go
@@ -0,0 +1,215 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metadata
+
+import (
+ "context"
+ "time"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+)
+
+// allowedFieldMaskPaths defines the allowed field mask paths that can be accessed for end devices from this package.
+// Calls to the entity registry require an IS roundtrip call which can be cross-continental. This must be done for a
+// high volume of end devices, so we want to limit the amount of data that is being transferred.
+var allowedFieldMaskPaths = []string{
+ "attributes",
+ "locations",
+}
+
+// EndDeviceRegistry interface for the identity server.
+type EndDeviceRegistry interface {
+ // Get returns an end device from the entity registry by its identifiers.
+ Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, paths []string) (*ttnpb.EndDevice, error)
+ // Set creates, updates or deletes an end device from the entity registry by its identifiers.
+ Set(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ paths []string,
+ f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error),
+ ) (*ttnpb.EndDevice, error)
+}
+
+type noopEndDeviceRegistry struct{}
+
+// Get implements EndDeviceRegistry.
+func (noopEndDeviceRegistry) Get(
+ _ context.Context,
+ _ *ttnpb.EndDeviceIdentifiers,
+ _ []string,
+) (*ttnpb.EndDevice, error) {
+ return &ttnpb.EndDevice{}, nil // nolint: nilnil
+}
+
+// Set implements EndDeviceRegistry.
+func (noopEndDeviceRegistry) Set(
+ _ context.Context,
+ _ *ttnpb.EndDeviceIdentifiers,
+ _ []string,
+ f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error),
+) (*ttnpb.EndDevice, error) {
+ if f == nil {
+ return &ttnpb.EndDevice{}, nil // nolint: nilnil
+ }
+
+ endDevice, _, err := f(&ttnpb.EndDevice{})
+ return endDevice, err
+}
+
+// NewNoopEndDeviceRegistry returns a noop EndDeviceRegistry.
+func NewNoopEndDeviceRegistry() EndDeviceRegistry {
+ return noopEndDeviceRegistry{}
+}
+
+type metricsEndDeviceRegistry struct {
+ inner EndDeviceRegistry
+}
+
+// Get implements EndDeviceRegistry.
+func (m *metricsEndDeviceRegistry) Get(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ paths []string,
+) (*ttnpb.EndDevice, error) {
+ registerMetadataRegistryRetrieval(ctx, endDeviceLabel)
+ return m.inner.Get(ctx, ids, paths)
+}
+
+// Set implements EndDeviceRegistry.
+func (m *metricsEndDeviceRegistry) Set(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ paths []string,
+ f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error),
+) (*ttnpb.EndDevice, error) {
+ registerMetadataRegistryUpdate(ctx, endDeviceLabel)
+ return m.inner.Set(ctx, ids, paths, f)
+}
+
+// NewMetricsEndDeviceRegistry returns an EndDeviceRegistry that collects metrics.
+func NewMetricsEndDeviceRegistry(inner EndDeviceRegistry) EndDeviceRegistry {
+ return &metricsEndDeviceRegistry{
+ inner: inner,
+ }
+}
+
+type clusterEndDeviceRegistry struct {
+ ClusterPeerAccess
+ timeout time.Duration
+}
+
+// Get implements EndDeviceRegistry.
+func (c clusterEndDeviceRegistry) Get(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ paths []string,
+) (*ttnpb.EndDevice, error) {
+ paths, err := processEndDeviceFieldMaskPaths(paths)
+ if err != nil {
+ return nil, err
+ }
+
+ cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ cl := ttnpb.NewEndDeviceRegistryClient(cc)
+ ctx, cancel := context.WithTimeout(ctx, c.timeout)
+ defer cancel()
+
+ dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{
+ EndDeviceIds: ids,
+ FieldMask: ttnpb.FieldMask(paths...),
+ }, c.WithClusterAuth())
+ if err != nil {
+ return nil, err
+ }
+
+ return dev, nil
+}
+
+// Set implements EndDeviceRegistry.
+func (c clusterEndDeviceRegistry) Set(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ paths []string,
+ f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error),
+) (*ttnpb.EndDevice, error) {
+ paths, err := processEndDeviceFieldMaskPaths(paths)
+ if err != nil {
+ return nil, err
+ }
+
+ cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ cl := ttnpb.NewEndDeviceRegistryClient(cc)
+ ctx, cancel := context.WithTimeout(ctx, c.timeout)
+ defer cancel()
+
+ dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{
+ EndDeviceIds: ids,
+ FieldMask: ttnpb.FieldMask(paths...),
+ }, c.WithClusterAuth())
+ if err != nil {
+ return nil, err
+ }
+
+ dev, paths, err = f(dev)
+ if err != nil || dev == nil {
+ return nil, err
+ }
+ dev, err = cl.Update(ctx, &ttnpb.UpdateEndDeviceRequest{
+ EndDevice: dev,
+ FieldMask: ttnpb.FieldMask(paths...),
+ }, c.WithClusterAuth())
+ if err != nil {
+ return nil, err
+ }
+
+ return dev, nil
+}
+
+// NewClusterEndDeviceRegistry returns an EndDeviceRegistry connected to the entity registry of the Identity Server.
+func NewClusterEndDeviceRegistry(cluster ClusterPeerAccess, timeout time.Duration) EndDeviceRegistry {
+ return &clusterEndDeviceRegistry{
+ ClusterPeerAccess: cluster,
+ timeout: timeout,
+ }
+}
+
+func processEndDeviceFieldMaskPaths(paths []string) ([]string, error) {
+ if len(paths) == 0 {
+ return allowedFieldMaskPaths, nil
+ }
+
+ if err := validateEndDevicePaths(paths); err != nil {
+ return nil, err
+ }
+
+ return paths, nil
+}
+
+func validateEndDevicePaths(paths []string) error {
+ allowedFieldMaskSet := ttnpb.FieldMaskPathsSet(allowedFieldMaskPaths)
+ if ok, firstNotAllowedPath := ttnpb.FieldMaskPathsSetContainsAll(allowedFieldMaskSet, paths...); !ok {
+ return errFieldMaskPathNotSupported.WithAttributes("path", firstNotAllowedPath)
+ }
+
+ return nil
+}
diff --git a/pkg/applicationserver/metadata/end_device_registry_test.go b/pkg/applicationserver/metadata/end_device_registry_test.go
new file mode 100644
index 0000000000..9aac154a89
--- /dev/null
+++ b/pkg/applicationserver/metadata/end_device_registry_test.go
@@ -0,0 +1,210 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metadata_test
+
+import (
+ "testing"
+ "time"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/errors"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata"
+ "go.thethings.network/lorawan-stack/v3/pkg/cluster"
+ "go.thethings.network/lorawan-stack/v3/pkg/component"
+ componenttest "go.thethings.network/lorawan-stack/v3/pkg/component/test"
+ "go.thethings.network/lorawan-stack/v3/pkg/config"
+ mockis "go.thethings.network/lorawan-stack/v3/pkg/identityserver/mock"
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+ "go.thethings.network/lorawan-stack/v3/pkg/util/test"
+ "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should"
+)
+
+var (
+ originalLocations = map[string]*ttnpb.Location{
+ "baz": {
+ Altitude: 12,
+ Latitude: 23,
+ },
+ }
+ locationsPatch = map[string]*ttnpb.Location{
+ "bzz": {
+ Altitude: 23,
+ Latitude: 34,
+ },
+ }
+
+ originalAttributes = map[string]string{
+ "attr1": "val1",
+ "attr2": "val2",
+ }
+
+ attributesPatch = map[string]string{
+ "attr3": "val3",
+ "attr4": "val4",
+ }
+)
+
+func TestClusterEndDeviceRegistry(t *testing.T) { // nolint:gocyclo
+ registeredEndDeviceIDs := &ttnpb.EndDeviceIdentifiers{
+ ApplicationIds: &ttnpb.ApplicationIdentifiers{
+ ApplicationId: "foo",
+ },
+ DeviceId: "bar",
+ }
+
+ t.Parallel()
+
+ a, ctx := test.New(t)
+ is, isAddr, closeIS := mockis.New(ctx)
+ defer closeIS()
+
+ registeredEndDevice := ttnpb.EndDevice{
+ Ids: registeredEndDeviceIDs,
+ Locations: originalLocations,
+ Attributes: originalAttributes,
+ }
+ is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice)
+
+ c := componenttest.NewComponent(t, &component.Config{
+ ServiceBase: config.ServiceBase{
+ Cluster: cluster.Config{
+ IdentityServer: isAddr,
+ },
+ },
+ })
+ componenttest.StartComponent(t, c)
+ defer c.Close()
+ mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY)
+
+ registry := metadata.NewClusterEndDeviceRegistry(c, 10*time.Second)
+
+ _, err := registry.Get(ctx, registeredEndDeviceIDs, []string{
+ "network_server_address", "application_server_address", "join_server_address",
+ })
+ a.So(errors.IsInvalidArgument(err), should.BeTrue)
+
+ dev, err := registry.Get(ctx, registeredEndDeviceIDs, []string{"attributes", "locations"})
+ if a.So(err, should.BeNil) {
+ a.So(dev, should.NotBeNil)
+
+ a.So(dev.Locations, should.NotBeNil)
+ a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations))
+ for k, v := range dev.Locations {
+ a.So(registeredEndDevice.Locations[k], should.Resemble, v)
+ }
+ for k, v := range originalLocations {
+ a.So(dev.Locations[k], should.Resemble, v)
+ }
+
+ a.So(dev.Attributes, should.NotBeNil)
+ a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes))
+ for k, v := range dev.Attributes {
+ a.So(registeredEndDevice.Attributes[k], should.Equal, v)
+ }
+ for k, v := range originalAttributes {
+ a.So(dev.Attributes[k], should.Equal, v)
+ }
+ }
+
+ _, err = registry.Set(ctx, registeredEndDeviceIDs, []string{
+ "network_server_address", "application_server_address", "join_server_address",
+ }, func(_ *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) {
+ return nil, nil, nil // nolint: nilnil
+ })
+ a.So(errors.IsInvalidArgument(err), should.BeTrue)
+
+ // Update location and attributes.
+ dev, err = registry.Set(ctx, registeredEndDeviceIDs, []string{"locations", "attributes"},
+ func(stored *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) {
+ if stored == nil {
+ return nil, nil, errors.New("not found")
+ }
+
+ if len(stored.Locations) == 0 {
+ stored.Locations = make(map[string]*ttnpb.Location, len(locationsPatch))
+ }
+
+ for k, l := range locationsPatch {
+ stored.Locations[k] = l
+ }
+
+ if len(stored.Attributes) == 0 {
+ stored.Attributes = make(map[string]string, len(attributesPatch))
+ }
+
+ for k, v := range attributesPatch {
+ stored.Attributes[k] = v
+ }
+
+ return stored, []string{"locations", "attributes"}, nil
+ },
+ )
+ if a.So(err, should.BeNil) {
+ a.So(dev, should.NotBeNil)
+
+ a.So(dev.Locations, should.NotBeNil)
+ a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations))
+ for k, v := range dev.Locations {
+ a.So(registeredEndDevice.Locations[k], should.Resemble, v)
+ }
+ for k, v := range originalLocations {
+ a.So(dev.Locations[k], should.Resemble, v)
+ }
+ for k, v := range locationsPatch {
+ a.So(dev.Locations[k], should.Resemble, v)
+ }
+
+ a.So(dev.Attributes, should.NotBeNil)
+ a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes))
+ for k, v := range dev.Attributes {
+ a.So(registeredEndDevice.Attributes[k], should.Equal, v)
+ }
+ for k, v := range originalAttributes {
+ a.So(dev.Attributes[k], should.Equal, v)
+ }
+ for k, v := range attributesPatch {
+ a.So(dev.Attributes[k], should.Equal, v)
+ }
+ }
+
+ dev, err = registry.Get(ctx, registeredEndDeviceIDs, []string{"attributes", "locations"})
+ if a.So(err, should.BeNil) {
+ a.So(dev, should.NotBeNil)
+
+ a.So(dev.Locations, should.NotBeNil)
+ a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations))
+ for k, v := range dev.Locations {
+ a.So(registeredEndDevice.Locations[k], should.Resemble, v)
+ }
+ for k, v := range originalLocations {
+ a.So(dev.Locations[k], should.Resemble, v)
+ }
+ for k, v := range locationsPatch {
+ a.So(dev.Locations[k], should.Resemble, v)
+ }
+
+ a.So(dev.Attributes, should.NotBeNil)
+ a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes))
+ for k, v := range dev.Attributes {
+ a.So(registeredEndDevice.Attributes[k], should.Equal, v)
+ }
+ for k, v := range originalAttributes {
+ a.So(dev.Attributes[k], should.Equal, v)
+ }
+ for k, v := range attributesPatch {
+ a.So(dev.Attributes[k], should.Equal, v)
+ }
+ }
+}
diff --git a/pkg/applicationserver/metadata/location_cache.go b/pkg/applicationserver/metadata/location_cache.go
deleted file mode 100644
index 6ad1a3de1a..0000000000
--- a/pkg/applicationserver/metadata/location_cache.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package metadata
-
-import (
- "context"
- "time"
-
- "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
-)
-
-// EndDeviceLocationCache is a cache for end device locations.
-type EndDeviceLocationCache interface {
- // Get retrieves the end device locations and the remaining TTL for the entry.
- Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error)
- // Set sets the end device locations.
- Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error
- // Delete removes the locations from the cache.
- Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error
-}
-
-type metricsEndDeviceLocationCache struct {
- inner EndDeviceLocationCache
-}
-
-// Get implements EndDeviceLocationCache.
-func (c *metricsEndDeviceLocationCache) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error) {
- m, storedAt, err := c.inner.Get(ctx, ids)
- if storedAt == nil {
- registerMetadataCacheMiss(ctx, locationLabel)
- } else {
- registerMetadataCacheHit(ctx, locationLabel)
- }
- return m, storedAt, err
-}
-
-// Set implements EndDeviceLocationCache.
-func (c *metricsEndDeviceLocationCache) Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error {
- return c.inner.Set(ctx, ids, update, ttl)
-}
-
-// Delete implements EndDeviceLocationCache.
-func (c *metricsEndDeviceLocationCache) Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error {
- return c.inner.Delete(ctx, ids)
-}
-
-// NewMetricsEndDeviceLocationCache constructs an EndDeviceLocationCache that collects metrics.
-func NewMetricsEndDeviceLocationCache(inner EndDeviceLocationCache) EndDeviceLocationCache {
- return &metricsEndDeviceLocationCache{
- inner: inner,
- }
-}
diff --git a/pkg/applicationserver/metadata/location_registry.go b/pkg/applicationserver/metadata/location_registry.go
deleted file mode 100644
index b1c1a5fcef..0000000000
--- a/pkg/applicationserver/metadata/location_registry.go
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package metadata
-
-import (
- "context"
- "time"
-
- "go.thethings.network/lorawan-stack/v3/pkg/cluster"
- "go.thethings.network/lorawan-stack/v3/pkg/errors"
- "go.thethings.network/lorawan-stack/v3/pkg/log"
- "go.thethings.network/lorawan-stack/v3/pkg/random"
- "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
- "go.thethings.network/lorawan-stack/v3/pkg/workerpool"
- "google.golang.org/grpc"
-)
-
-// EndDeviceLocationRegistry is a registry for end device locations.
-type EndDeviceLocationRegistry interface {
- // Get retrieves the end device locations.
- Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error)
- // Merge merges the end device locations.
- Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error)
-}
-
-type noopEndDeviceLocationRegistry struct{}
-
-// Get implements EndDeviceLocationRegistry.
-func (noopEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) {
- return nil, nil
-}
-
-// Merge implements EndDeviceLocationRegistry.
-func (noopEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) {
- return update, nil
-}
-
-// NewNoopEndDeviceLocationRegistry returns a noop EndDeviceLocationRegistry.
-func NewNoopEndDeviceLocationRegistry() EndDeviceLocationRegistry {
- return noopEndDeviceLocationRegistry{}
-}
-
-type metricsEndDeviceLocationRegistry struct {
- inner EndDeviceLocationRegistry
-}
-
-// Get implements EndDeviceLocationRegistry.
-func (m *metricsEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) {
- registerMetadataRegistryRetrieval(ctx, locationLabel)
- return m.inner.Get(ctx, ids)
-}
-
-// Merge implements EndDeviceLocationRegistry.
-func (m *metricsEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) {
- registerMetadataRegistryUpdate(ctx, locationLabel)
- return m.inner.Merge(ctx, ids, update)
-}
-
-// NewMetricsEndDeviceLocationRegistry returns an EndDeviceLocationRegistry that collects metrics.
-func NewMetricsEndDeviceLocationRegistry(inner EndDeviceLocationRegistry) EndDeviceLocationRegistry {
- return &metricsEndDeviceLocationRegistry{
- inner: inner,
- }
-}
-
-// ClusterPeerAccess provides access to cluster peers.
-type ClusterPeerAccess interface {
- GetPeerConn(ctx context.Context, role ttnpb.ClusterRole, ids cluster.EntityIdentifiers) (*grpc.ClientConn, error)
- WithClusterAuth() grpc.CallOption
-}
-
-var endDeviceLocationFieldMask = ttnpb.FieldMask("locations")
-
-type clusterEndDeviceLocationRegistry struct {
- ClusterPeerAccess
- timeout time.Duration
-}
-
-// Get implements EndDeviceLocationRegistry.
-func (c clusterEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) {
- cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil)
- if err != nil {
- return nil, err
- }
- cl := ttnpb.NewEndDeviceRegistryClient(cc)
- ctx, cancel := context.WithTimeout(ctx, c.timeout)
- defer cancel()
- dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{
- EndDeviceIds: ids,
- FieldMask: endDeviceLocationFieldMask,
- }, c.WithClusterAuth())
- if err != nil {
- return nil, err
- }
- return dev.Locations, nil
-}
-
-// Merge implements EndDeviceLocationRegistry.
-func (c clusterEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) {
- cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil)
- if err != nil {
- return nil, err
- }
- cl := ttnpb.NewEndDeviceRegistryClient(cc)
- ctx, cancel := context.WithTimeout(ctx, c.timeout)
- defer cancel()
- dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{
- EndDeviceIds: ids,
- FieldMask: endDeviceLocationFieldMask,
- }, c.WithClusterAuth())
- if err != nil {
- return nil, err
- }
- if len(update) == 0 {
- return dev.Locations, nil
- }
- if dev.Locations == nil {
- dev.Locations = make(map[string]*ttnpb.Location, len(update))
- }
- for k, l := range update {
- dev.Locations[k] = l
- }
- _, err = cl.Update(ctx, &ttnpb.UpdateEndDeviceRequest{
- EndDevice: &ttnpb.EndDevice{
- Ids: ids,
- Locations: dev.Locations,
- },
- FieldMask: endDeviceLocationFieldMask,
- }, c.WithClusterAuth())
- if err != nil {
- return nil, err
- }
- return dev.Locations, nil
-}
-
-// NewClusterEndDeviceLocationRegistry returns an EndDeviceLocationRegistry connected to the Entity Registry.
-func NewClusterEndDeviceLocationRegistry(cluster ClusterPeerAccess, timeout time.Duration) EndDeviceLocationRegistry {
- return &clusterEndDeviceLocationRegistry{
- ClusterPeerAccess: cluster,
- timeout: timeout,
- }
-}
-
-type cachedEndDeviceLocationRegistry struct {
- registry EndDeviceLocationRegistry
- cache EndDeviceLocationCache
-
- minRefreshInterval time.Duration
- maxRefreshInterval time.Duration
- ttl time.Duration
-
- replicationPool workerpool.WorkerPool[*ttnpb.EndDeviceIdentifiers]
-}
-
-// Get implements EndDeviceLocationRegistry.
-func (c *cachedEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) {
- locations, storedAt, err := c.cache.Get(ctx, ids)
- switch {
- case err != nil && !errors.IsNotFound(err):
- return nil, err
- case err != nil && errors.IsNotFound(err):
- locations = nil
- case err == nil:
- age := time.Since(*storedAt)
- if age <= c.minRefreshInterval {
- // If the object is younger than the minimum refresh interval, just return the cached value.
- return locations, nil
- }
- if remaining := c.maxRefreshInterval - age; remaining > 0 {
- // If the objects age is between the minimum and maximum refresh interval, check if we should asynchronously
- // refresh the cache.
- window := c.maxRefreshInterval - c.minRefreshInterval
- threshold := time.Duration(random.Int63n(int64(window)))
- // remaining is the remaining window of the refresh interval in the (0, window) interval.
- // threshold is a uniformly distributed duration in the [0, window) interval.
- if remaining >= threshold {
- return locations, nil
- }
- }
- }
- if err := c.replicationPool.Publish(ctx, ids); err != nil {
- log.FromContext(ctx).WithError(err).Warn("Failed to publish end device locations replication request")
- }
- return locations, nil
-}
-
-// Merge implements EndDeviceLocationRegistry.
-func (c *cachedEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) {
- locations, err := c.registry.Merge(ctx, ids, update)
- if err != nil {
- return nil, err
- }
- if err := c.cache.Set(ctx, ids, locations, c.ttl); err != nil {
- return nil, err
- }
- return locations, nil
-}
-
-// NewCachedEndDeviceLocationRegistry returns an EndDeviceLocationRegistry that caches the responses of the provided EndDeviceLocationRegistry in the provided
-// EndDeviceLocationCache. On cache miss, the registry will retrieve and cache the locations asynchronously.
-// Items whose TTL is within the soft TTL window have a chance to trigger an asynchronous cache synchronization event on location retrieval.
-// The probability of a synchronization event increases linearly between the soft TTL (0%) and the hard TTL (100%).
-func NewCachedEndDeviceLocationRegistry(ctx context.Context, c workerpool.Component, registry EndDeviceLocationRegistry, cache EndDeviceLocationCache, minRefreshInterval, maxRefreshInterval, ttl time.Duration) EndDeviceLocationRegistry {
- st := &cachedEndDeviceLocationRegistry{
- registry: registry,
- cache: cache,
-
- minRefreshInterval: minRefreshInterval,
- maxRefreshInterval: maxRefreshInterval,
- ttl: ttl,
-
- replicationPool: workerpool.NewWorkerPool(workerpool.Config[*ttnpb.EndDeviceIdentifiers]{
- Component: c,
- Context: ctx,
- Name: "replicate_end_device_locations",
- Handler: func(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) {
- locations, err := registry.Get(ctx, ids)
- if err != nil {
- log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations")
- return
- }
- if err := cache.Set(ctx, ids, locations, ttl); err != nil {
- log.FromContext(ctx).WithError(err).Warn("Failed to cache end device locations")
- return
- }
- },
- }),
- }
- return st
-}
diff --git a/pkg/applicationserver/metadata/location_registry_test.go b/pkg/applicationserver/metadata/location_registry_test.go
deleted file mode 100644
index f366942a04..0000000000
--- a/pkg/applicationserver/metadata/location_registry_test.go
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package metadata_test
-
-import (
- "context"
- "testing"
- "time"
-
- "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata"
- "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis"
- "go.thethings.network/lorawan-stack/v3/pkg/cluster"
- "go.thethings.network/lorawan-stack/v3/pkg/component"
- componenttest "go.thethings.network/lorawan-stack/v3/pkg/component/test"
- "go.thethings.network/lorawan-stack/v3/pkg/config"
- mockis "go.thethings.network/lorawan-stack/v3/pkg/identityserver/mock"
- "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
- "go.thethings.network/lorawan-stack/v3/pkg/util/test"
- "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should"
-)
-
-func mustHavePeer(ctx context.Context, c *component.Component, role ttnpb.ClusterRole) {
- for i := 0; i < 20; i++ {
- time.Sleep(20 * time.Millisecond)
- if _, err := c.GetPeer(ctx, role, nil); err == nil {
- return
- }
- }
- panic("could not connect to peer")
-}
-
-var (
- registeredEndDeviceIDs = &ttnpb.EndDeviceIdentifiers{
- ApplicationIds: &ttnpb.ApplicationIdentifiers{
- ApplicationId: "foo",
- },
- DeviceId: "bar",
- }
- originalLocations = map[string]*ttnpb.Location{
- "baz": {
- Altitude: 12,
- Latitude: 23,
- },
- }
- locationsPatch = map[string]*ttnpb.Location{
- "bzz": {
- Altitude: 23,
- Latitude: 34,
- },
- }
- Timeout = (1 << 7) * test.Delay
-)
-
-func TestClusterEndDeviceLocationRegistry(t *testing.T) {
- a, ctx := test.New(t)
- is, isAddr, closeIS := mockis.New(ctx)
- defer closeIS()
-
- registeredEndDevice := ttnpb.EndDevice{
- Ids: registeredEndDeviceIDs,
- Locations: originalLocations,
- }
- is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice)
-
- c := componenttest.NewComponent(t, &component.Config{
- ServiceBase: config.ServiceBase{
- Cluster: cluster.Config{
- IdentityServer: isAddr,
- },
- },
- })
- componenttest.StartComponent(t, c)
- defer c.Close()
- mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY)
-
- registry := metadata.NewClusterEndDeviceLocationRegistry(c, 10*time.Second)
-
- locations, err := registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- locations, err = registry.Merge(ctx, registeredEndDeviceIDs, locationsPatch)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-}
-
-func TestCachedEndDeviceLocationRegistry(t *testing.T) {
- a, ctx := test.New(t)
- is, isAddr, closeIS := mockis.New(ctx)
- defer closeIS()
-
- registeredEndDevice := ttnpb.EndDevice{
- Ids: registeredEndDeviceIDs,
- Locations: originalLocations,
- }
- is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice)
-
- c := componenttest.NewComponent(t, &component.Config{
- ServiceBase: config.ServiceBase{
- Cluster: cluster.Config{
- IdentityServer: isAddr,
- },
- },
- })
- componenttest.StartComponent(t, c)
- defer c.Close()
- mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY)
-
- registry := metadata.NewClusterEndDeviceLocationRegistry(c, 4*Timeout)
- cl, flush := test.NewRedis(ctx, "metadata_redis_test")
- defer flush()
- cache := &redis.EndDeviceLocationCache{
- Redis: cl,
- }
- registry = metadata.NewCachedEndDeviceLocationRegistry(
- ctx, c, registry, cache, 4*Timeout, 8*Timeout, 16*Timeout,
- )
-
- locations, err := registry.Get(ctx, registeredEndDeviceIDs)
- a.So(err, should.BeNil)
- a.So(locations, should.HaveLength, 0)
-
- // Wait for the cache to be populated asynchronously.
- time.Sleep(Timeout)
-
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(originalLocations))
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- locations, err = registry.Merge(ctx, registeredEndDeviceIDs, locationsPatch)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- // Wait for the entry to be evicted.
- time.Sleep(20 * Timeout)
-
- // There is no cached location anymore, and we have triggered an asynchronous refresh.
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- a.So(err, should.BeNil)
- a.So(locations, should.HaveLength, 0)
-
- time.Sleep(Timeout)
-
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- // Simulate a network partition.
- closeIS()
- time.Sleep(Timeout)
-
- // Do a read that will trigger an asynchronous cache refresh.
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-
- // Wait for the partition to be detected asynchronously.
- time.Sleep(Timeout)
-
- // We now serve stale data.
- locations, err = registry.Get(ctx, registeredEndDeviceIDs)
- if a.So(err, should.BeNil) {
- a.So(locations, should.NotBeNil)
- a.So(len(locations), should.Equal, len(registeredEndDevice.Locations))
- for k, v := range locations {
- a.So(registeredEndDevice.Locations[k], should.Resemble, v)
- }
- for k, v := range originalLocations {
- a.So(locations[k], should.Resemble, v)
- }
- for k, v := range locationsPatch {
- a.So(locations[k], should.Resemble, v)
- }
- }
-}
diff --git a/pkg/applicationserver/metadata/metadata.go b/pkg/applicationserver/metadata/metadata.go
new file mode 100644
index 0000000000..fb442095c6
--- /dev/null
+++ b/pkg/applicationserver/metadata/metadata.go
@@ -0,0 +1,21 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package metadata contains the metadata registry clients.
+package metadata
+
+import "go.thethings.network/lorawan-stack/v3/pkg/errors"
+
+var errFieldMaskPathNotSupported = errors.DefineInvalidArgument(
+ "field_mask_path_not_supported", "field mask path `{path}` is not supported")
diff --git a/pkg/applicationserver/metadata/metadata_util_test.go b/pkg/applicationserver/metadata/metadata_util_test.go
new file mode 100644
index 0000000000..56407cc45b
--- /dev/null
+++ b/pkg/applicationserver/metadata/metadata_util_test.go
@@ -0,0 +1,33 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metadata_test
+
+import (
+ "context"
+ "time"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/component"
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+)
+
+func mustHavePeer(ctx context.Context, c *component.Component, role ttnpb.ClusterRole) { // nolint: unparam
+ for i := 0; i < 20; i++ {
+ time.Sleep(20 * time.Millisecond)
+ if _, err := c.GetPeer(ctx, role, nil); err == nil {
+ return
+ }
+ }
+ panic("could not connect to peer")
+}
diff --git a/pkg/applicationserver/metadata/observability.go b/pkg/applicationserver/metadata/observability.go
index 64ff2f6bc3..75a3c93408 100644
--- a/pkg/applicationserver/metadata/observability.go
+++ b/pkg/applicationserver/metadata/observability.go
@@ -22,28 +22,13 @@ import (
)
const (
- subsystem = "as_metadata"
- metadataLabel = "metadata"
- locationLabel = "location"
+ subsystem = "as_metadata"
+ metadataLabel = "metadata"
+ locationLabel = "location"
+ endDeviceLabel = "end_device"
)
var metaMetrics = &metadataMetrics{
- cacheHits: metrics.NewCounterVec(
- prometheus.CounterOpts{
- Subsystem: subsystem,
- Name: "cache_hits_total",
- Help: "Total number of metadata cache hits",
- },
- []string{metadataLabel},
- ),
- cacheMisses: metrics.NewCounterVec(
- prometheus.CounterOpts{
- Subsystem: subsystem,
- Name: "cache_misses_total",
- Help: "Total number of metadata cache misses",
- },
- []string{metadataLabel},
- ),
registryRetrievals: metrics.NewCounterVec(
prometheus.CounterOpts{
Subsystem: subsystem,
@@ -67,40 +52,24 @@ func init() {
}
type metadataMetrics struct {
- cacheHits *prometheus.CounterVec
- cacheMisses *prometheus.CounterVec
registryRetrievals *prometheus.CounterVec
registryUpdates *prometheus.CounterVec
}
func (m metadataMetrics) Describe(ch chan<- *prometheus.Desc) {
- m.cacheHits.Describe(ch)
- m.cacheMisses.Describe(ch)
m.registryRetrievals.Describe(ch)
m.registryUpdates.Describe(ch)
}
func (m metadataMetrics) Collect(ch chan<- prometheus.Metric) {
- m.cacheHits.Collect(ch)
- m.cacheMisses.Collect(ch)
m.registryRetrievals.Collect(ch)
m.registryUpdates.Collect(ch)
}
-func registerMetadataCacheHit(ctx context.Context, metadata string) {
- metaMetrics.cacheHits.WithLabelValues(metadata).Inc()
- metaMetrics.cacheMisses.WithLabelValues(metadata)
-}
-
-func registerMetadataCacheMiss(ctx context.Context, metadata string) {
- metaMetrics.cacheHits.WithLabelValues(metadata)
- metaMetrics.cacheMisses.WithLabelValues(metadata).Inc()
-}
-
-func registerMetadataRegistryRetrieval(ctx context.Context, metadata string) {
+func registerMetadataRegistryRetrieval(_ context.Context, metadata string) {
metaMetrics.registryRetrievals.WithLabelValues(metadata).Inc()
}
-func registerMetadataRegistryUpdate(ctx context.Context, metadata string) {
+func registerMetadataRegistryUpdate(_ context.Context, metadata string) {
metaMetrics.registryUpdates.WithLabelValues(metadata).Inc()
}
diff --git a/pkg/applicationserver/metadata/redis/end_device_cache.go b/pkg/applicationserver/metadata/redis/end_device_cache.go
new file mode 100644
index 0000000000..f9e48a1de7
--- /dev/null
+++ b/pkg/applicationserver/metadata/redis/end_device_cache.go
@@ -0,0 +1,116 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package redis
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "time"
+
+ "github.com/redis/go-redis/v9"
+ ttnredis "go.thethings.network/lorawan-stack/v3/pkg/redis"
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+ "go.thethings.network/lorawan-stack/v3/pkg/unique"
+)
+
+// EndDeviceCache is a Redis end device cache.
+type EndDeviceCache struct {
+ Redis *ttnredis.Client
+}
+
+func (r *EndDeviceCache) uidKey(uid string) string {
+ return r.Redis.Key("uid", uid)
+}
+
+// Get returns the end device by the identifiers.
+func (r *EndDeviceCache) Get(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+) (*ttnpb.EndDevice, *time.Time, error) {
+ uidKey := r.uidKey(unique.ID(ctx, ids))
+ m, err := r.Redis.HGetAll(ctx, uidKey).Result()
+ if err != nil {
+ return nil, nil, ttnredis.ConvertError(err)
+ }
+ if len(m) == 0 {
+ return nil, nil, errCacheMiss.New()
+ }
+
+ var storedAt time.Time
+ if s, ok := m[storedAtMarker]; ok {
+ n, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ storedAt = time.Unix(0, n)
+ }
+ if s, ok := m[errorMarker]; ok {
+ details := &ttnpb.ErrorDetails{}
+ if err := ttnredis.UnmarshalProto(s, details); err != nil {
+ return nil, nil, err
+ }
+ return nil, &storedAt, ttnpb.ErrorDetailsFromProto(details)
+ }
+ if marshalledDevice, ok := m[endDeviceMarker]; ok {
+ dev := new(ttnpb.EndDevice)
+ if err := ttnredis.UnmarshalProto(marshalledDevice, dev); err != nil {
+ return nil, nil, err
+ }
+
+ return dev, &storedAt, nil
+ }
+
+ return nil, nil, errCacheEntryMalformed
+}
+
+// Set updates the end device by its identifiers.
+func (r *EndDeviceCache) Set(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ dev *ttnpb.EndDevice,
+ ttl time.Duration,
+) error {
+ marshalledEndDevice, err := ttnredis.MarshalProto(dev)
+ if err != nil {
+ return err
+ }
+ pairs := []string{
+ storedAtMarker,
+ fmt.Sprintf("%v", time.Now().UnixNano()),
+ endDeviceMarker,
+ marshalledEndDevice,
+ }
+
+ uidKey := r.uidKey(unique.ID(ctx, ids))
+ if _, err := r.Redis.Pipelined(ctx, func(p redis.Pipeliner) error {
+ p.Del(ctx, uidKey)
+ p.HSet(ctx, uidKey, pairs)
+ p.PExpire(ctx, uidKey, ttl)
+ return nil
+ }); err != nil {
+ return ttnredis.ConvertError(err)
+ }
+ return nil
+}
+
+// Delete removes the end device by the identifiers.
+func (r *EndDeviceCache) Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error {
+ uidKey := r.uidKey(unique.ID(ctx, ids))
+ if err := r.Redis.Del(ctx, uidKey).Err(); err != nil {
+ return ttnredis.ConvertError(err)
+ }
+ return nil
+}
diff --git a/pkg/applicationserver/metadata/redis/end_device_cache_test.go b/pkg/applicationserver/metadata/redis/end_device_cache_test.go
new file mode 100644
index 0000000000..5aed3ad45a
--- /dev/null
+++ b/pkg/applicationserver/metadata/redis/end_device_cache_test.go
@@ -0,0 +1,107 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package redis_test
+
+import (
+ "testing"
+ "time"
+
+ "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis"
+ "go.thethings.network/lorawan-stack/v3/pkg/errors"
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+ "go.thethings.network/lorawan-stack/v3/pkg/util/test"
+ "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should"
+)
+
+var (
+ attributesA = map[string]string{
+ "attr1": "val1",
+ "attr2": "val2",
+ }
+ attributesB = map[string]string{
+ "attr3": "val3",
+ }
+)
+
+func TestEndDeviceCache(t *testing.T) {
+ t.Parallel()
+
+ endDevice := &ttnpb.EndDevice{
+ Ids: registeredEndDeviceIDs,
+ Attributes: attributesA,
+ }
+
+ a, ctx := test.New(t)
+ cl, flush := test.NewRedis(ctx, "metadata_redis_test")
+ defer flush()
+ cache := redis.EndDeviceCache{Redis: cl}
+
+ _, _, err := cache.Get(ctx, registeredEndDeviceIDs)
+ a.So(err, should.NotBeNil)
+ a.So(errors.IsNotFound(err), should.BeTrue)
+
+ storeTime := time.Now()
+ err = cache.Set(ctx, registeredEndDeviceIDs, endDevice, Timeout)
+ a.So(err, should.BeNil)
+
+ dev, storedAt, err := cache.Get(ctx, endDevice.Ids)
+ if a.So(err, should.BeNil) {
+ if a.So(storedAt, should.NotBeNil) {
+ a.So(*storedAt, should.HappenOnOrAfter, storeTime)
+ }
+ a.So(dev, should.Resemble, endDevice)
+ }
+
+ endDevice.Attributes = attributesB
+
+ storeTime = time.Now()
+ err = cache.Set(ctx, registeredEndDeviceIDs, endDevice, Timeout)
+ a.So(err, should.BeNil)
+
+ dev, storedAt, err = cache.Get(ctx, registeredEndDeviceIDs)
+ if a.So(err, should.BeNil) {
+ if a.So(storedAt, should.NotBeNil) {
+ a.So(*storedAt, should.HappenOnOrAfter, storeTime)
+ }
+ a.So(dev, should.Resemble, endDevice)
+ }
+
+ err = cache.Delete(ctx, registeredEndDeviceIDs)
+ a.So(err, should.BeNil)
+
+ _, _, err = cache.Get(ctx, registeredEndDeviceIDs)
+ a.So(err, should.NotBeNil)
+ a.So(errors.IsNotFound(err), should.BeTrue)
+
+ endDevice.Attributes = attributesA
+
+ storeTime = time.Now()
+ err = cache.Set(ctx, registeredEndDeviceIDs, endDevice, Timeout)
+ a.So(err, should.BeNil)
+
+ dev, storedAt, err = cache.Get(ctx, registeredEndDeviceIDs)
+ if a.So(err, should.BeNil) {
+ if a.So(storedAt, should.NotBeNil) {
+ a.So(*storedAt, should.HappenOnOrAfter, storeTime)
+ }
+ a.So(dev, should.Resemble, endDevice)
+ }
+
+ time.Sleep(2 * Timeout)
+
+ _, _, err = cache.Get(ctx, registeredEndDeviceIDs)
+ a.So(err, should.NotBeNil)
+ a.So(errors.IsNotFound(err), should.BeTrue)
+}
diff --git a/pkg/applicationserver/metadata/redis/location_cache.go b/pkg/applicationserver/metadata/redis/location_cache.go
index c8221e109e..d27d6f6469 100644
--- a/pkg/applicationserver/metadata/redis/location_cache.go
+++ b/pkg/applicationserver/metadata/redis/location_cache.go
@@ -21,7 +21,6 @@ import (
"time"
"github.com/redis/go-redis/v9"
- "go.thethings.network/lorawan-stack/v3/pkg/errors"
ttnredis "go.thethings.network/lorawan-stack/v3/pkg/redis"
"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
"go.thethings.network/lorawan-stack/v3/pkg/unique"
@@ -36,17 +35,11 @@ func (r *EndDeviceLocationCache) uidKey(uid string) string {
return r.Redis.Key("uid", uid)
}
-const (
- // storedAtMarker is used to store the timestamp of the last Set operation.
- storedAtMarker = "_stored_at"
- // errorMarker is used to store errors.
- errorMarker = "_error"
-)
-
-var errCacheMiss = errors.DefineNotFound("cache_miss", "cache miss")
-
// Get returns the locations by the end device identifiers.
-func (r *EndDeviceLocationCache) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error) {
+func (r *EndDeviceLocationCache) Get(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+) (map[string]*ttnpb.Location, *time.Time, error) {
uidKey := r.uidKey(unique.ID(ctx, ids))
m, err := r.Redis.HGetAll(ctx, uidKey).Result()
if err != nil {
@@ -86,7 +79,12 @@ func (r *EndDeviceLocationCache) Get(ctx context.Context, ids *ttnpb.EndDeviceId
}
// Set updates the locations by the end device identifiers.
-func (r *EndDeviceLocationCache) Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error {
+func (r *EndDeviceLocationCache) Set(
+ ctx context.Context,
+ ids *ttnpb.EndDeviceIdentifiers,
+ update map[string]*ttnpb.Location,
+ ttl time.Duration,
+) error {
pairs := append(make([]string, 0, 2*len(update)+2), storedAtMarker, fmt.Sprintf("%v", time.Now().UnixNano()))
for k, v := range update {
s, err := ttnredis.MarshalProto(v)
diff --git a/pkg/applicationserver/metadata/redis/location_cache_test.go b/pkg/applicationserver/metadata/redis/location_cache_test.go
index eee514b062..706e036da6 100644
--- a/pkg/applicationserver/metadata/redis/location_cache_test.go
+++ b/pkg/applicationserver/metadata/redis/location_cache_test.go
@@ -26,13 +26,6 @@ import (
)
var (
- registeredEndDeviceIDs = &ttnpb.EndDeviceIdentifiers{
- ApplicationIds: &ttnpb.ApplicationIdentifiers{
- ApplicationId: "foo",
- },
- DeviceId: "bar",
- }
-
locationA = map[string]*ttnpb.Location{
"foo": {
Latitude: 123,
@@ -48,13 +41,11 @@ var (
Latitude: 567,
},
}
-
- errUnavailable = errors.DefineUnavailable("unavailable", "unavailable")
-
- Timeout = (1 << 8) * test.Delay
)
func TestLocationCache(t *testing.T) {
+ t.Parallel()
+
a, ctx := test.New(t)
cl, flush := test.NewRedis(ctx, "metadata_redis_test")
defer flush()
diff --git a/pkg/applicationserver/metadata/redis/redis.go b/pkg/applicationserver/metadata/redis/redis.go
new file mode 100644
index 0000000000..b997c79759
--- /dev/null
+++ b/pkg/applicationserver/metadata/redis/redis.go
@@ -0,0 +1,37 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package redis provides a Redis-based cache for end device metadata.
+package redis
+
+import (
+ "go.thethings.network/lorawan-stack/v3/pkg/errors"
+)
+
+const (
+ // nolint: godot
+ // endDeviceMarker is used to store an end device.
+ endDeviceMarker = "_end_device"
+ // nolint: godot
+ // errorMarker is used to store errors.
+ errorMarker = "_error"
+ // nolint: godot
+ // storedAtMarker is used to store the timestamp of the last Set operation.
+ storedAtMarker = "_stored_at"
+)
+
+var (
+ errCacheEntryMalformed = errors.DefineCorruption("cache_entry_malformed", "cache entry malformed")
+ errCacheMiss = errors.DefineNotFound("cache_miss", "cache miss")
+)
diff --git a/pkg/applicationserver/metadata/redis/redis_util_test.go b/pkg/applicationserver/metadata/redis/redis_util_test.go
new file mode 100644
index 0000000000..5991749652
--- /dev/null
+++ b/pkg/applicationserver/metadata/redis/redis_util_test.go
@@ -0,0 +1,31 @@
+// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package redis_test
+
+import (
+ "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
+ "go.thethings.network/lorawan-stack/v3/pkg/util/test"
+)
+
+var (
+ registeredEndDeviceIDs = &ttnpb.EndDeviceIdentifiers{
+ ApplicationIds: &ttnpb.ApplicationIdentifiers{
+ ApplicationId: "foo",
+ },
+ DeviceId: "bar",
+ }
+
+ Timeout = (1 << 8) * test.Delay
+)
diff --git a/pkg/networkserver/grpc_deviceregistry.go b/pkg/networkserver/grpc_deviceregistry.go
index 756ca39e4c..d050c43a3f 100644
--- a/pkg/networkserver/grpc_deviceregistry.go
+++ b/pkg/networkserver/grpc_deviceregistry.go
@@ -3021,6 +3021,13 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
"mac_state.pending_relay_downlink.raw_payload",
diff --git a/pkg/ttnpb/applicationserver.pb.paths.fm.go b/pkg/ttnpb/applicationserver.pb.paths.fm.go
index f3b7f770d2..9d5a558dea 100644
--- a/pkg/ttnpb/applicationserver.pb.paths.fm.go
+++ b/pkg/ttnpb/applicationserver.pb.paths.fm.go
@@ -99,6 +99,7 @@ var NsAsHandleUplinkRequestFieldPathsTopLevel = []string{
}
var EncodeDownlinkRequestFieldPathsNested = []string{
"downlink",
+ "downlink.attributes",
"downlink.class_b_c",
"downlink.class_b_c.absolute_time",
"downlink.class_b_c.gateways",
@@ -112,8 +113,22 @@ var EncodeDownlinkRequestFieldPathsNested = []string{
"downlink.f_cnt",
"downlink.f_port",
"downlink.frm_payload",
+ "downlink.locations",
+ "downlink.network_ids",
+ "downlink.network_ids.cluster_address",
+ "downlink.network_ids.cluster_id",
+ "downlink.network_ids.net_id",
+ "downlink.network_ids.ns_id",
+ "downlink.network_ids.tenant_address",
+ "downlink.network_ids.tenant_id",
"downlink.priority",
"downlink.session_key_id",
+ "downlink.version_ids",
+ "downlink.version_ids.band_id",
+ "downlink.version_ids.brand_id",
+ "downlink.version_ids.firmware_version",
+ "downlink.version_ids.hardware_version",
+ "downlink.version_ids.model_id",
"end_device_ids",
"end_device_ids.application_ids",
"end_device_ids.application_ids.application_id",
@@ -140,6 +155,7 @@ var EncodeDownlinkRequestFieldPathsTopLevel = []string{
}
var EncodeDownlinkResponseFieldPathsNested = []string{
"downlink",
+ "downlink.attributes",
"downlink.class_b_c",
"downlink.class_b_c.absolute_time",
"downlink.class_b_c.gateways",
@@ -153,8 +169,22 @@ var EncodeDownlinkResponseFieldPathsNested = []string{
"downlink.f_cnt",
"downlink.f_port",
"downlink.frm_payload",
+ "downlink.locations",
+ "downlink.network_ids",
+ "downlink.network_ids.cluster_address",
+ "downlink.network_ids.cluster_id",
+ "downlink.network_ids.net_id",
+ "downlink.network_ids.ns_id",
+ "downlink.network_ids.tenant_address",
+ "downlink.network_ids.tenant_id",
"downlink.priority",
"downlink.session_key_id",
+ "downlink.version_ids",
+ "downlink.version_ids.band_id",
+ "downlink.version_ids.brand_id",
+ "downlink.version_ids.firmware_version",
+ "downlink.version_ids.hardware_version",
+ "downlink.version_ids.model_id",
}
var EncodeDownlinkResponseFieldPathsTopLevel = []string{
@@ -175,6 +205,7 @@ var DecodeUplinkRequestFieldPathsNested = []string{
"uplink.app_s_key.encrypted_key",
"uplink.app_s_key.kek_label",
"uplink.app_s_key.key",
+ "uplink.attributes",
"uplink.confirmed",
"uplink.consumed_airtime",
"uplink.decoded_payload",
@@ -250,6 +281,7 @@ var DecodeUplinkResponseFieldPathsNested = []string{
"uplink.app_s_key.encrypted_key",
"uplink.app_s_key.kek_label",
"uplink.app_s_key.key",
+ "uplink.attributes",
"uplink.confirmed",
"uplink.consumed_airtime",
"uplink.decoded_payload",
@@ -311,6 +343,7 @@ var DecodeUplinkResponseFieldPathsTopLevel = []string{
}
var DecodeDownlinkRequestFieldPathsNested = []string{
"downlink",
+ "downlink.attributes",
"downlink.class_b_c",
"downlink.class_b_c.absolute_time",
"downlink.class_b_c.gateways",
@@ -324,8 +357,22 @@ var DecodeDownlinkRequestFieldPathsNested = []string{
"downlink.f_cnt",
"downlink.f_port",
"downlink.frm_payload",
+ "downlink.locations",
+ "downlink.network_ids",
+ "downlink.network_ids.cluster_address",
+ "downlink.network_ids.cluster_id",
+ "downlink.network_ids.net_id",
+ "downlink.network_ids.ns_id",
+ "downlink.network_ids.tenant_address",
+ "downlink.network_ids.tenant_id",
"downlink.priority",
"downlink.session_key_id",
+ "downlink.version_ids",
+ "downlink.version_ids.band_id",
+ "downlink.version_ids.brand_id",
+ "downlink.version_ids.firmware_version",
+ "downlink.version_ids.hardware_version",
+ "downlink.version_ids.model_id",
"end_device_ids",
"end_device_ids.application_ids",
"end_device_ids.application_ids.application_id",
@@ -352,6 +399,7 @@ var DecodeDownlinkRequestFieldPathsTopLevel = []string{
}
var DecodeDownlinkResponseFieldPathsNested = []string{
"downlink",
+ "downlink.attributes",
"downlink.class_b_c",
"downlink.class_b_c.absolute_time",
"downlink.class_b_c.gateways",
@@ -365,8 +413,22 @@ var DecodeDownlinkResponseFieldPathsNested = []string{
"downlink.f_cnt",
"downlink.f_port",
"downlink.frm_payload",
+ "downlink.locations",
+ "downlink.network_ids",
+ "downlink.network_ids.cluster_address",
+ "downlink.network_ids.cluster_id",
+ "downlink.network_ids.net_id",
+ "downlink.network_ids.ns_id",
+ "downlink.network_ids.tenant_address",
+ "downlink.network_ids.tenant_id",
"downlink.priority",
"downlink.session_key_id",
+ "downlink.version_ids",
+ "downlink.version_ids.band_id",
+ "downlink.version_ids.brand_id",
+ "downlink.version_ids.firmware_version",
+ "downlink.version_ids.hardware_version",
+ "downlink.version_ids.model_id",
}
var DecodeDownlinkResponseFieldPathsTopLevel = []string{
diff --git a/pkg/ttnpb/end_device.go b/pkg/ttnpb/end_device.go
index 41985da6de..1e79c4d18c 100644
--- a/pkg/ttnpb/end_device.go
+++ b/pkg/ttnpb/end_device.go
@@ -1829,6 +1829,8 @@ func (v *MACState) FieldIsZero(p string) bool {
return v.LorawanVersion == 0
case "pending_application_downlink":
return v.PendingApplicationDownlink == nil
+ case "pending_application_downlink.attributes":
+ return v.PendingApplicationDownlink.FieldIsZero("attributes")
case "pending_application_downlink.class_b_c":
return v.PendingApplicationDownlink.FieldIsZero("class_b_c")
case "pending_application_downlink.class_b_c.absolute_time":
@@ -1855,10 +1857,38 @@ func (v *MACState) FieldIsZero(p string) bool {
return v.PendingApplicationDownlink.FieldIsZero("f_port")
case "pending_application_downlink.frm_payload":
return v.PendingApplicationDownlink.FieldIsZero("frm_payload")
+ case "pending_application_downlink.locations":
+ return v.PendingApplicationDownlink.FieldIsZero("locations")
+ case "pending_application_downlink.network_ids":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids")
+ case "pending_application_downlink.network_ids.cluster_address":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.cluster_address")
+ case "pending_application_downlink.network_ids.cluster_id":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.cluster_id")
+ case "pending_application_downlink.network_ids.net_id":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.net_id")
+ case "pending_application_downlink.network_ids.ns_id":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.ns_id")
+ case "pending_application_downlink.network_ids.tenant_address":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.tenant_address")
+ case "pending_application_downlink.network_ids.tenant_id":
+ return v.PendingApplicationDownlink.FieldIsZero("network_ids.tenant_id")
case "pending_application_downlink.priority":
return v.PendingApplicationDownlink.FieldIsZero("priority")
case "pending_application_downlink.session_key_id":
return v.PendingApplicationDownlink.FieldIsZero("session_key_id")
+ case "pending_application_downlink.version_ids":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids")
+ case "pending_application_downlink.version_ids.band_id":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids.band_id")
+ case "pending_application_downlink.version_ids.brand_id":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids.brand_id")
+ case "pending_application_downlink.version_ids.firmware_version":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids.firmware_version")
+ case "pending_application_downlink.version_ids.hardware_version":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids.hardware_version")
+ case "pending_application_downlink.version_ids.model_id":
+ return v.PendingApplicationDownlink.FieldIsZero("version_ids.model_id")
case "pending_join_request":
return v.PendingJoinRequest == nil
case "pending_join_request.cf_list":
@@ -2998,3 +3028,25 @@ func (d *EndDevice) UpdateTimestamps(src *EndDevice) {
// EndDeviceFieldPathsNestedWithoutWrappers is the set of EndDevice nested paths without the wrapper paths.
var EndDeviceFieldPathsNestedWithoutWrappers = FieldsWithoutWrappers(EndDeviceFieldPathsNested)
+
+// FieldIsZero returns whether path p is zero.
+func (v *NetworkIdentifiers) FieldIsZero(p string) bool {
+ if v == nil {
+ return true
+ }
+ switch p {
+ case "cluster_address":
+ return v.ClusterAddress == ""
+ case "cluster_id":
+ return v.ClusterId == ""
+ case "net_id":
+ return len(v.NetId) == 0
+ case "ns_id":
+ return len(v.NsId) == 0
+ case "tenant_address":
+ return v.TenantAddress == ""
+ case "tenant_id": // nolint:goconst
+ return v.TenantId == ""
+ }
+ panic(fmt.Sprintf("unknown path '%s'", p))
+}
diff --git a/pkg/ttnpb/end_device.pb.paths.fm.go b/pkg/ttnpb/end_device.pb.paths.fm.go
index 089bfe8399..07447f5e95 100644
--- a/pkg/ttnpb/end_device.pb.paths.fm.go
+++ b/pkg/ttnpb/end_device.pb.paths.fm.go
@@ -1268,6 +1268,7 @@ var MACStateFieldPathsNested = []string{
"last_network_initiated_downlink_at",
"lorawan_version",
"pending_application_downlink",
+ "pending_application_downlink.attributes",
"pending_application_downlink.class_b_c",
"pending_application_downlink.class_b_c.absolute_time",
"pending_application_downlink.class_b_c.gateways",
@@ -1281,8 +1282,22 @@ var MACStateFieldPathsNested = []string{
"pending_application_downlink.f_cnt",
"pending_application_downlink.f_port",
"pending_application_downlink.frm_payload",
+ "pending_application_downlink.locations",
+ "pending_application_downlink.network_ids",
+ "pending_application_downlink.network_ids.cluster_address",
+ "pending_application_downlink.network_ids.cluster_id",
+ "pending_application_downlink.network_ids.net_id",
+ "pending_application_downlink.network_ids.ns_id",
+ "pending_application_downlink.network_ids.tenant_address",
+ "pending_application_downlink.network_ids.tenant_id",
"pending_application_downlink.priority",
"pending_application_downlink.session_key_id",
+ "pending_application_downlink.version_ids",
+ "pending_application_downlink.version_ids.band_id",
+ "pending_application_downlink.version_ids.brand_id",
+ "pending_application_downlink.version_ids.firmware_version",
+ "pending_application_downlink.version_ids.hardware_version",
+ "pending_application_downlink.version_ids.model_id",
"pending_join_request",
"pending_join_request.cf_list",
"pending_join_request.cf_list.ch_masks",
@@ -1758,6 +1773,7 @@ var EndDeviceFieldPathsNested = []string{
"mac_state.last_network_initiated_downlink_at",
"mac_state.lorawan_version",
"mac_state.pending_application_downlink",
+ "mac_state.pending_application_downlink.attributes",
"mac_state.pending_application_downlink.class_b_c",
"mac_state.pending_application_downlink.class_b_c.absolute_time",
"mac_state.pending_application_downlink.class_b_c.gateways",
@@ -1771,8 +1787,22 @@ var EndDeviceFieldPathsNested = []string{
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.locations",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
+ "mac_state.pending_application_downlink.version_ids",
+ "mac_state.pending_application_downlink.version_ids.band_id",
+ "mac_state.pending_application_downlink.version_ids.brand_id",
+ "mac_state.pending_application_downlink.version_ids.firmware_version",
+ "mac_state.pending_application_downlink.version_ids.hardware_version",
+ "mac_state.pending_application_downlink.version_ids.model_id",
"mac_state.pending_join_request",
"mac_state.pending_join_request.cf_list",
"mac_state.pending_join_request.cf_list.ch_masks",
@@ -1974,6 +2004,7 @@ var EndDeviceFieldPathsNested = []string{
"pending_mac_state.last_network_initiated_downlink_at",
"pending_mac_state.lorawan_version",
"pending_mac_state.pending_application_downlink",
+ "pending_mac_state.pending_application_downlink.attributes",
"pending_mac_state.pending_application_downlink.class_b_c",
"pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -1987,8 +2018,22 @@ var EndDeviceFieldPathsNested = []string{
"pending_mac_state.pending_application_downlink.f_cnt",
"pending_mac_state.pending_application_downlink.f_port",
"pending_mac_state.pending_application_downlink.frm_payload",
+ "pending_mac_state.pending_application_downlink.locations",
+ "pending_mac_state.pending_application_downlink.network_ids",
+ "pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"pending_mac_state.pending_application_downlink.priority",
"pending_mac_state.pending_application_downlink.session_key_id",
+ "pending_mac_state.pending_application_downlink.version_ids",
+ "pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "pending_mac_state.pending_application_downlink.version_ids.model_id",
"pending_mac_state.pending_join_request",
"pending_mac_state.pending_join_request.cf_list",
"pending_mac_state.pending_join_request.cf_list.ch_masks",
@@ -2586,6 +2631,7 @@ var CreateEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.last_network_initiated_downlink_at",
"end_device.mac_state.lorawan_version",
"end_device.mac_state.pending_application_downlink",
+ "end_device.mac_state.pending_application_downlink.attributes",
"end_device.mac_state.pending_application_downlink.class_b_c",
"end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -2599,8 +2645,22 @@ var CreateEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.pending_application_downlink.f_cnt",
"end_device.mac_state.pending_application_downlink.f_port",
"end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device.mac_state.pending_application_downlink.locations",
+ "end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.mac_state.pending_application_downlink.priority",
"end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device.mac_state.pending_join_request",
"end_device.mac_state.pending_join_request.cf_list",
"end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -2802,6 +2862,7 @@ var CreateEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device.pending_mac_state.lorawan_version",
"end_device.pending_mac_state.pending_application_downlink",
+ "end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -2815,8 +2876,22 @@ var CreateEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.pending_mac_state.pending_application_downlink.priority",
"end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device.pending_mac_state.pending_join_request",
"end_device.pending_mac_state.pending_join_request.cf_list",
"end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
@@ -3346,6 +3421,7 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.last_network_initiated_downlink_at",
"end_device.mac_state.lorawan_version",
"end_device.mac_state.pending_application_downlink",
+ "end_device.mac_state.pending_application_downlink.attributes",
"end_device.mac_state.pending_application_downlink.class_b_c",
"end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -3359,8 +3435,22 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.pending_application_downlink.f_cnt",
"end_device.mac_state.pending_application_downlink.f_port",
"end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device.mac_state.pending_application_downlink.locations",
+ "end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.mac_state.pending_application_downlink.priority",
"end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device.mac_state.pending_join_request",
"end_device.mac_state.pending_join_request.cf_list",
"end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -3562,6 +3652,7 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device.pending_mac_state.lorawan_version",
"end_device.pending_mac_state.pending_application_downlink",
+ "end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -3575,8 +3666,22 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.pending_mac_state.pending_application_downlink.priority",
"end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device.pending_mac_state.pending_join_request",
"end_device.pending_mac_state.pending_join_request.cf_list",
"end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
@@ -4157,6 +4262,7 @@ var SetEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.last_network_initiated_downlink_at",
"end_device.mac_state.lorawan_version",
"end_device.mac_state.pending_application_downlink",
+ "end_device.mac_state.pending_application_downlink.attributes",
"end_device.mac_state.pending_application_downlink.class_b_c",
"end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -4170,8 +4276,22 @@ var SetEndDeviceRequestFieldPathsNested = []string{
"end_device.mac_state.pending_application_downlink.f_cnt",
"end_device.mac_state.pending_application_downlink.f_port",
"end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device.mac_state.pending_application_downlink.locations",
+ "end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.mac_state.pending_application_downlink.priority",
"end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device.mac_state.pending_join_request",
"end_device.mac_state.pending_join_request.cf_list",
"end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -4373,6 +4493,7 @@ var SetEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device.pending_mac_state.lorawan_version",
"end_device.pending_mac_state.pending_application_downlink",
+ "end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -4386,8 +4507,22 @@ var SetEndDeviceRequestFieldPathsNested = []string{
"end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.pending_mac_state.pending_application_downlink.priority",
"end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device.pending_mac_state.pending_join_request",
"end_device.pending_mac_state.pending_join_request.cf_list",
"end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
@@ -4934,6 +5069,7 @@ var EndDeviceTemplateFieldPathsNested = []string{
"end_device.mac_state.last_network_initiated_downlink_at",
"end_device.mac_state.lorawan_version",
"end_device.mac_state.pending_application_downlink",
+ "end_device.mac_state.pending_application_downlink.attributes",
"end_device.mac_state.pending_application_downlink.class_b_c",
"end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -4947,8 +5083,22 @@ var EndDeviceTemplateFieldPathsNested = []string{
"end_device.mac_state.pending_application_downlink.f_cnt",
"end_device.mac_state.pending_application_downlink.f_port",
"end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device.mac_state.pending_application_downlink.locations",
+ "end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.mac_state.pending_application_downlink.priority",
"end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device.mac_state.pending_join_request",
"end_device.mac_state.pending_join_request.cf_list",
"end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -5150,6 +5300,7 @@ var EndDeviceTemplateFieldPathsNested = []string{
"end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device.pending_mac_state.lorawan_version",
"end_device.pending_mac_state.pending_application_downlink",
+ "end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -5163,8 +5314,22 @@ var EndDeviceTemplateFieldPathsNested = []string{
"end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.pending_mac_state.pending_application_downlink.priority",
"end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device.pending_mac_state.pending_join_request",
"end_device.pending_mac_state.pending_join_request.cf_list",
"end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
diff --git a/pkg/ttnpb/field_mask_validation.go b/pkg/ttnpb/field_mask_validation.go
index d07e53d09a..42e9acdebc 100644
--- a/pkg/ttnpb/field_mask_validation.go
+++ b/pkg/ttnpb/field_mask_validation.go
@@ -439,6 +439,7 @@ var nsEndDeviceReadFieldPaths = [...]string{
"mac_state.last_network_initiated_downlink_at",
"mac_state.lorawan_version",
"mac_state.pending_application_downlink",
+ "mac_state.pending_application_downlink.attributes",
"mac_state.pending_application_downlink.class_b_c",
"mac_state.pending_application_downlink.class_b_c.absolute_time",
"mac_state.pending_application_downlink.class_b_c.gateways",
@@ -447,8 +448,22 @@ var nsEndDeviceReadFieldPaths = [...]string{
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.locations",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
+ "mac_state.pending_application_downlink.version_ids",
+ "mac_state.pending_application_downlink.version_ids.band_id",
+ "mac_state.pending_application_downlink.version_ids.brand_id",
+ "mac_state.pending_application_downlink.version_ids.firmware_version",
+ "mac_state.pending_application_downlink.version_ids.hardware_version",
+ "mac_state.pending_application_downlink.version_ids.model_id",
"mac_state.pending_relay_downlink",
"mac_state.pending_relay_downlink.raw_payload",
"mac_state.pending_requests",
@@ -1358,6 +1373,13 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
"mac_state.pending_relay_downlink",
diff --git a/pkg/ttnpb/messages.go b/pkg/ttnpb/messages.go
index d7cfc2a436..18e06b66b5 100644
--- a/pkg/ttnpb/messages.go
+++ b/pkg/ttnpb/messages.go
@@ -71,6 +71,8 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool {
return true
}
switch p {
+ case "attributes":
+ return v.Attributes == nil
case "class_b_c":
return v.ClassBC == nil
case "class_b_c.absolute_time":
@@ -79,6 +81,12 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool {
return v.ClassBC.FieldIsZero("gateways")
case "confirmed":
return !v.Confirmed
+ case "confirmed_retry":
+ return v.ConfirmedRetry == nil
+ case "confirmed_retry.attempt":
+ return v.ConfirmedRetry.FieldIsZero("attempt")
+ case "confirmed_retry.max_attempts":
+ return v.ConfirmedRetry.FieldIsZero("max_attempts")
case "correlation_ids":
return v.CorrelationIds == nil
case "decoded_payload":
@@ -91,16 +99,38 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool {
return v.FPort == 0
case "frm_payload":
return v.FrmPayload == nil
+ case "locations":
+ return v.Locations == nil
+ case "network_ids": // nolint: goconst
+ return v.NetworkIds == nil
+ case "network_ids.cluster_address":
+ return v.NetworkIds.FieldIsZero("cluster_address")
+ case "network_ids.cluster_id":
+ return v.NetworkIds.FieldIsZero("cluster_id")
+ case "network_ids.net_id":
+ return v.NetworkIds.FieldIsZero("net_id")
+ case "network_ids.ns_id":
+ return v.NetworkIds.FieldIsZero("ns_id")
+ case "network_ids.tenant_address":
+ return v.NetworkIds.FieldIsZero("tenant_address")
+ case "network_ids.tenant_id":
+ return v.NetworkIds.FieldIsZero("tenant_id")
case "priority":
return v.Priority == 0
case "session_key_id":
return v.SessionKeyId == nil
- case "confirmed_retry":
- return v.ConfirmedRetry == nil
- case "confirmed_retry.attempt":
- return v.ConfirmedRetry.FieldIsZero("attempt")
- case "confirmed_retry.max_attempts":
- return v.ConfirmedRetry.FieldIsZero("max_attempts")
+ case "version_ids":
+ return v.VersionIds == nil
+ case "version_ids.band_id":
+ return v.VersionIds.FieldIsZero("band_id")
+ case "version_ids.brand_id":
+ return v.VersionIds.FieldIsZero("brand_id")
+ case "version_ids.firmware_version":
+ return v.VersionIds.FieldIsZero("firmware_version")
+ case "version_ids.hardware_version":
+ return v.VersionIds.FieldIsZero("hardware_version")
+ case "version_ids.model_id":
+ return v.VersionIds.FieldIsZero("model_id")
}
panic(fmt.Sprintf("unknown path '%s'", p))
}
diff --git a/pkg/ttnpb/messages.pb.go b/pkg/ttnpb/messages.pb.go
index 0d65cc1b9f..22323c0fb5 100644
--- a/pkg/ttnpb/messages.pb.go
+++ b/pkg/ttnpb/messages.pb.go
@@ -715,6 +715,8 @@ type ApplicationUplink struct {
// Received via the DevStatus MAC command at last_dev_status_received_at or earlier.
// Set by the Network Server while handling the message.
LastBatteryPercentage *LastBatteryPercentage `protobuf:"bytes,20,opt,name=last_battery_percentage,json=lastBatteryPercentage,proto3" json:"last_battery_percentage,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,21,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationUplink) Reset() {
@@ -889,6 +891,13 @@ func (x *ApplicationUplink) GetLastBatteryPercentage() *LastBatteryPercentage {
return nil
}
+func (x *ApplicationUplink) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type ApplicationUplinkNormalized struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -924,6 +933,8 @@ type ApplicationUplinkNormalized struct {
VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,13,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
// Network identifiers, set by the Network Server that handles the message.
NetworkIds *NetworkIdentifiers `protobuf:"bytes,14,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationUplinkNormalized) Reset() {
@@ -1056,6 +1067,13 @@ func (x *ApplicationUplinkNormalized) GetNetworkIds() *NetworkIdentifiers {
return nil
}
+func (x *ApplicationUplinkNormalized) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type ApplicationLocation struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1135,6 +1153,14 @@ type ApplicationJoinAccept struct {
PendingSession bool `protobuf:"varint,4,opt,name=pending_session,json=pendingSession,proto3" json:"pending_session,omitempty"`
// Server time when the Network Server received the message.
ReceivedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=received_at,json=receivedAt,proto3" json:"received_at,omitempty"`
+ // End device location metadata, set by the Application Server while handling the message.
+ Locations map[string]*Location `protobuf:"bytes,9,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // End device version identifiers, set by the Application Server while handling the message.
+ VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,10,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIds *NetworkIdentifiers `protobuf:"bytes,11,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,12,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationJoinAccept) Reset() {
@@ -1204,6 +1230,34 @@ func (x *ApplicationJoinAccept) GetReceivedAt() *timestamppb.Timestamp {
return nil
}
+func (x *ApplicationJoinAccept) GetLocations() map[string]*Location {
+ if x != nil {
+ return x.Locations
+ }
+ return nil
+}
+
+func (x *ApplicationJoinAccept) GetVersionIds() *EndDeviceVersionIdentifiers {
+ if x != nil {
+ return x.VersionIds
+ }
+ return nil
+}
+
+func (x *ApplicationJoinAccept) GetNetworkIds() *NetworkIdentifiers {
+ if x != nil {
+ return x.NetworkIds
+ }
+ return nil
+}
+
+func (x *ApplicationJoinAccept) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type ApplicationDownlink struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1233,6 +1287,14 @@ type ApplicationDownlink struct {
Priority TxSchedulePriority `protobuf:"varint,8,opt,name=priority,proto3,enum=ttn.lorawan.v3.TxSchedulePriority" json:"priority,omitempty"`
CorrelationIds []string `protobuf:"bytes,9,rep,name=correlation_ids,json=correlationIds,proto3" json:"correlation_ids,omitempty"`
ConfirmedRetry *ApplicationDownlink_ConfirmedRetry `protobuf:"bytes,11,opt,name=confirmed_retry,json=confirmedRetry,proto3" json:"confirmed_retry,omitempty"`
+ // End device location metadata, set by the Application Server while handling the message.
+ Locations map[string]*Location `protobuf:"bytes,12,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // End device version identifiers, set by the Application Server while handling the message.
+ VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,13,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIds *NetworkIdentifiers `protobuf:"bytes,14,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationDownlink) Reset() {
@@ -1344,6 +1406,34 @@ func (x *ApplicationDownlink) GetConfirmedRetry() *ApplicationDownlink_Confirmed
return nil
}
+func (x *ApplicationDownlink) GetLocations() map[string]*Location {
+ if x != nil {
+ return x.Locations
+ }
+ return nil
+}
+
+func (x *ApplicationDownlink) GetVersionIds() *EndDeviceVersionIdentifiers {
+ if x != nil {
+ return x.VersionIds
+ }
+ return nil
+}
+
+func (x *ApplicationDownlink) GetNetworkIds() *NetworkIdentifiers {
+ if x != nil {
+ return x.NetworkIds
+ }
+ return nil
+}
+
+func (x *ApplicationDownlink) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type ApplicationDownlinks struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1398,6 +1488,14 @@ type ApplicationDownlinkFailed struct {
Downlink *ApplicationDownlink `protobuf:"bytes,1,opt,name=downlink,proto3" json:"downlink,omitempty"`
Error *ErrorDetails `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
+ // End device location metadata, set by the Application Server while handling the message.
+ Locations map[string]*Location `protobuf:"bytes,3,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // End device version identifiers, set by the Application Server while handling the message.
+ VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,4,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIds *NetworkIdentifiers `protobuf:"bytes,5,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,6,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationDownlinkFailed) Reset() {
@@ -1446,6 +1544,34 @@ func (x *ApplicationDownlinkFailed) GetError() *ErrorDetails {
return nil
}
+func (x *ApplicationDownlinkFailed) GetLocations() map[string]*Location {
+ if x != nil {
+ return x.Locations
+ }
+ return nil
+}
+
+func (x *ApplicationDownlinkFailed) GetVersionIds() *EndDeviceVersionIdentifiers {
+ if x != nil {
+ return x.VersionIds
+ }
+ return nil
+}
+
+func (x *ApplicationDownlinkFailed) GetNetworkIds() *NetworkIdentifiers {
+ if x != nil {
+ return x.NetworkIds
+ }
+ return nil
+}
+
+func (x *ApplicationDownlinkFailed) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type ApplicationInvalidatedDownlinks struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1454,6 +1580,14 @@ type ApplicationInvalidatedDownlinks struct {
Downlinks []*ApplicationDownlink `protobuf:"bytes,1,rep,name=downlinks,proto3" json:"downlinks,omitempty"`
LastFCntDown uint32 `protobuf:"varint,2,opt,name=last_f_cnt_down,json=lastFCntDown,proto3" json:"last_f_cnt_down,omitempty"`
SessionKeyId []byte `protobuf:"bytes,3,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"`
+ // End device location metadata, set by the Application Server while handling the message.
+ Locations map[string]*Location `protobuf:"bytes,4,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // End device version identifiers, set by the Application Server while handling the message.
+ VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,5,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIds *NetworkIdentifiers `protobuf:"bytes,6,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,7,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationInvalidatedDownlinks) Reset() {
@@ -1509,6 +1643,34 @@ func (x *ApplicationInvalidatedDownlinks) GetSessionKeyId() []byte {
return nil
}
+func (x *ApplicationInvalidatedDownlinks) GetLocations() map[string]*Location {
+ if x != nil {
+ return x.Locations
+ }
+ return nil
+}
+
+func (x *ApplicationInvalidatedDownlinks) GetVersionIds() *EndDeviceVersionIdentifiers {
+ if x != nil {
+ return x.VersionIds
+ }
+ return nil
+}
+
+func (x *ApplicationInvalidatedDownlinks) GetNetworkIds() *NetworkIdentifiers {
+ if x != nil {
+ return x.NetworkIds
+ }
+ return nil
+}
+
+func (x *ApplicationInvalidatedDownlinks) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
type DownlinkQueueOperationErrorDetails struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1603,6 +1765,14 @@ type ApplicationServiceData struct {
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Data *structpb.Struct `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // End device location metadata, set by the Application Server while handling the message.
+ Locations map[string]*Location `protobuf:"bytes,3,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // End device version identifiers, set by the Application Server while handling the message.
+ VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,4,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"`
+ // Network identifiers, set by the Network Server that handles the message.
+ NetworkIds *NetworkIdentifiers `protobuf:"bytes,5,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"`
+ // Attributes for devices, set by the Application Server while handling the message.
+ Attributes map[string]string `protobuf:"bytes,6,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ApplicationServiceData) Reset() {
@@ -1651,6 +1821,34 @@ func (x *ApplicationServiceData) GetData() *structpb.Struct {
return nil
}
+func (x *ApplicationServiceData) GetLocations() map[string]*Location {
+ if x != nil {
+ return x.Locations
+ }
+ return nil
+}
+
+func (x *ApplicationServiceData) GetVersionIds() *EndDeviceVersionIdentifiers {
+ if x != nil {
+ return x.VersionIds
+ }
+ return nil
+}
+
+func (x *ApplicationServiceData) GetNetworkIds() *NetworkIdentifiers {
+ if x != nil {
+ return x.NetworkIds
+ }
+ return nil
+}
+
+func (x *ApplicationServiceData) GetAttributes() map[string]string {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
// Application uplink message.
type ApplicationUp struct {
state protoimpl.MessageState
@@ -2044,7 +2242,7 @@ type ApplicationDownlink_ClassBC struct {
func (x *ApplicationDownlink_ClassBC) Reset() {
*x = ApplicationDownlink_ClassBC{}
if protoimpl.UnsafeEnabled {
- mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[22]
+ mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2057,7 +2255,7 @@ func (x *ApplicationDownlink_ClassBC) String() string {
func (*ApplicationDownlink_ClassBC) ProtoMessage() {}
func (x *ApplicationDownlink_ClassBC) ProtoReflect() protoreflect.Message {
- mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[22]
+ mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[26]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2102,7 +2300,7 @@ type ApplicationDownlink_ConfirmedRetry struct {
func (x *ApplicationDownlink_ConfirmedRetry) Reset() {
*x = ApplicationDownlink_ConfirmedRetry{}
if protoimpl.UnsafeEnabled {
- mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[23]
+ mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2115,7 +2313,7 @@ func (x *ApplicationDownlink_ConfirmedRetry) String() string {
func (*ApplicationDownlink_ConfirmedRetry) ProtoMessage() {}
func (x *ApplicationDownlink_ConfirmedRetry) ProtoReflect() protoreflect.Message {
- mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[23]
+ mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[27]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2289,7 +2487,7 @@ var file_ttn_lorawan_v3_messages_proto_rawDesc = []byte{
0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
0x03, 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, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x22, 0xf4, 0x09,
+ 0x70, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x22, 0xbe, 0x0b,
0x0a, 0x11, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c,
0x69, 0x6e, 0x6b, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b,
0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05,
@@ -2363,389 +2561,581 @@ var file_ttn_lorawan_v3_messages_proto_rawDesc = []byte{
0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x61, 0x73, 0x74, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72,
0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x52, 0x15, 0x6c, 0x61, 0x73,
0x74, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61,
- 0x67, 0x65, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04,
- 0x08, 0x01, 0x10, 0x01, 0x22, 0xb4, 0x07, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c,
- 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
- 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42,
- 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b,
- 0x65, 0x79, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0d, 0xfa, 0x42, 0x0a, 0x2a, 0x08, 0x18, 0xff, 0x01, 0x28, 0x01,
- 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f,
- 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12,
- 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6d, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04,
- 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
- 0x12, 0x50, 0x0a, 0x12, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x70,
- 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52,
- 0x11, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f,
- 0x61, 0x64, 0x12, 0x3e, 0x0a, 0x1b, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64,
- 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67,
- 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69,
- 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e,
- 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
- 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
- 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12,
- 0x40, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28,
+ 0x67, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+ 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a,
+ 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d,
+ 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a,
+ 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8,
+ 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a,
+ 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76,
+ 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
+ 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x88,
+ 0x09, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70,
+ 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2e,
+ 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10,
+ 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x24,
+ 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0d,
+ 0xfa, 0x42, 0x0a, 0x2a, 0x08, 0x18, 0xff, 0x01, 0x28, 0x01, 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66,
+ 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6d,
+ 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
+ 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x50, 0x0a, 0x12, 0x6e, 0x6f,
+ 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
+ 0x18, 0x05, 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, 0x42,
+ 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x6e, 0x6f, 0x72, 0x6d, 0x61,
+ 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3e, 0x0a, 0x1b,
+ 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f,
+ 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x19, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79,
+ 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0b,
+ 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
- 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x08, 0xfa,
- 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
- 0x73, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74,
- 0x18, 0x09, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65,
- 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66,
- 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d,
- 0x65, 0x64, 0x5f, 0x61, 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
- 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, 0x6e,
- 0x73, 0x75, 0x6d, 0x65, 0x64, 0x41, 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x09,
- 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
- 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69,
- 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x4c, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
- 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74,
- 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64,
- 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65,
- 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
- 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f,
- 0x69, 0x64, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
- 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f,
- 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e,
- 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
- 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a,
- 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74,
- 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
- 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc5, 0x02, 0x0a, 0x13,
- 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a,
- 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
- 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01,
- 0x02, 0x10, 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8a, 0x01,
- 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e,
- 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c,
- 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
- 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10,
- 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d,
- 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39,
- 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a,
- 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74,
- 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
- 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
- 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08,
- 0x01, 0x10, 0x00, 0x22, 0xd4, 0x02, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2e, 0x0a,
- 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52,
- 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x37, 0x0a,
- 0x09, 0x61, 0x70, 0x70, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76,
- 0x33, 0x2e, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x61,
- 0x70, 0x70, 0x53, 0x4b, 0x65, 0x79, 0x12, 0x58, 0x0a, 0x15, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69,
- 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18,
- 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x14, 0x69, 0x6e, 0x76, 0x61,
- 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73,
- 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73,
- 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69,
- 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63,
- 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2,
- 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74,
- 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xd5, 0x09, 0x0a, 0x13, 0x41,
- 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
- 0x6e, 0x6b, 0x12, 0xcd, 0x01, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b,
- 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, 0x42,
- 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74,
- 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67,
- 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f,
- 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x77, 0x48,
- 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x47, 0x67, 0x69, 0x74,
- 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67,
- 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f,
- 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42,
- 0x79, 0x74, 0x65, 0x73, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79,
- 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0d, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x2a, 0x06, 0x18, 0xff, 0x01, 0x38, 0xe0, 0x01, 0x52,
- 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0xc8, 0x01, 0x0a, 0x0b,
- 0x66, 0x72, 0x6d, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
- 0x0c, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0xff, 0x01, 0xf2, 0xaa, 0x19, 0x99,
- 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68,
- 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65,
- 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d,
- 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69,
- 0x6e, 0x2e, 0x4e, 0x65, 0x77, 0x48, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61,
- 0x67, 0x22, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68,
- 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65,
- 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d,
- 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69,
- 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x66, 0x72, 0x6d, 0x50,
- 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x40, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65,
- 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 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, 0x0e, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65,
- 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, 0x6f,
- 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e,
- 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x64, 0x65, 0x63, 0x6f,
- 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e,
- 0x67, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18,
- 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64,
- 0x12, 0x47, 0x0a, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x63, 0x18, 0x07, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
- 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43,
- 0x52, 0x07, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x12, 0x48, 0x0a, 0x08, 0x70, 0x72, 0x69,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x74,
+ 0x76, 0x33, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72,
+ 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x08, 0x73, 0x65, 0x74,
+ 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74,
0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53,
- 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42,
- 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72,
- 0x69, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, 0x42,
- 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72,
- 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x5b, 0x0a, 0x0f, 0x63, 0x6f,
- 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x0b, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
- 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
- 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
- 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x1a, 0x9b, 0x01, 0x0a, 0x07, 0x43, 0x6c, 0x61, 0x73,
- 0x73, 0x42, 0x43, 0x12, 0x45, 0x0a, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x18,
- 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x47, 0x61,
- 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73,
- 0x52, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x61, 0x62,
- 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 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, 0x0c, 0x61,
- 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19,
- 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x80, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72,
- 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x74, 0x74, 0x65,
- 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d,
- 0x70, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70,
- 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33,
- 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0x64, 0x20,
- 0x00, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x3a, 0x08,
- 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01,
- 0x10, 0x01, 0x22, 0x59, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64, 0x6f,
- 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e,
- 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41,
- 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
- 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x22, 0xae, 0x01,
- 0x0a, 0x19, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x08, 0x64,
- 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e,
- 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41,
- 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
- 0x6e, 0x6b, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x64, 0x6f,
- 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, 0x61,
- 0x69, 0x6c, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x65,
- 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc5,
- 0x01, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e,
- 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
- 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18,
- 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e,
- 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x25, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x5f,
- 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c,
- 0x6c, 0x61, 0x73, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2e, 0x0a, 0x0e,
- 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x03,
- 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c,
- 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x3a, 0x08, 0xf2, 0xaa,
- 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x91, 0x05, 0x0a, 0x22, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
- 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0xc8, 0x01,
- 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
- 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, 0x43,
- 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa,
- 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67,
- 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77,
- 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63,
- 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d,
- 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3f,
- 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74,
- 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61,
- 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
- 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52,
- 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73,
- 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
- 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73,
- 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f,
- 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
- 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0xd7, 0x01,
- 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64,
- 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, 0x0a,
- 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02,
- 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, 0x01,
- 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69,
- 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61,
- 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67,
- 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, 0x45,
- 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68,
- 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72,
- 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b,
- 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61,
- 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
- 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3d, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69,
- 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69,
- 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80,
- 0x10, 0x52, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
- 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e,
- 0x67, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e,
- 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d,
- 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x22, 0x69, 0x0a, 0x16, 0x41, 0x70,
- 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
- 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b,
- 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 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, 0x04, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x08, 0xf2, 0xaa, 0x19,
- 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x94, 0x09, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64,
- 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
- 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
- 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52,
- 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x35, 0x0a,
- 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04,
- 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x49, 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64,
- 0x5f, 0x61, 0x74, 0x18, 0x0c, 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, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41,
- 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, 0x73,
- 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10,
+ 0x01, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x45, 0x0a, 0x0b, 0x72,
+ 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x42, 0x08, 0xfa, 0x42,
+ 0x05, 0xb2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64,
+ 0x41, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18,
+ 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64,
+ 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x5f, 0x61, 0x69, 0x72,
+ 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x41,
+ 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0d,
- 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5a, 0x0a,
- 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a,
- 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d,
+ 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18,
+ 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
+ 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+ 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
+ 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43,
+ 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0e, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e,
+ 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+ 0x49, 0x64, 0x73, 0x12, 0x92, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61,
- 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e,
- 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x0b, 0x6a, 0x6f, 0x69,
- 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
+ 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22,
+ 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d,
+ 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29,
+ 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74,
+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74,
+ 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+ 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a,
+ 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc5, 0x02, 0x0a, 0x13, 0x41, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x6c,
+ 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e,
+ 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c,
+ 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10,
+ 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8a, 0x01, 0x0a, 0x0a,
+ 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
+ 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76,
+ 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22,
+ 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d,
+ 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29,
+ 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74,
+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72,
+ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10,
+ 0x00, 0x22, 0xe1, 0x06, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2e, 0x0a, 0x0e, 0x73,
+ 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73,
+ 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x09, 0x61,
+ 0x70, 0x70, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
- 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41,
- 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63,
- 0x65, 0x70, 0x74, 0x12, 0x48, 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f,
- 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
- 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00,
- 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x4a, 0x0a,
- 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x61, 0x63, 0x6b, 0x18, 0x06,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77,
- 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x61, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76,
- 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
- 0x6b, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
- 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29,
+ 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x61, 0x70, 0x70,
+ 0x53, 0x4b, 0x65, 0x79, 0x12, 0x58, 0x0a, 0x15, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
+ 0x74, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x03, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x14, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69,
+ 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x27,
+ 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
+ 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
+ 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69,
+ 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02,
+ 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x52,
+ 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
+ 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f,
+ 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
+ 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66,
+ 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73,
+ 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18,
+ 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
+ 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64,
+ 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f,
+ 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8c, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e,
+ 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70,
+ 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18,
+ 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b,
+ 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d,
+ 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f,
+ 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19,
+ 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xde, 0x0d, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0xcd, 0x01,
+ 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80,
+ 0x10, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75,
+ 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65,
+ 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73,
+ 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x77, 0x48, 0x65, 0x78, 0x42, 0x79, 0x74,
+ 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75,
+ 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65,
+ 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73,
+ 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52,
+ 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a,
+ 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0b, 0xfa,
+ 0x42, 0x08, 0x2a, 0x06, 0x18, 0xff, 0x01, 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72,
+ 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
+ 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0xc8, 0x01, 0x0a, 0x0b, 0x66, 0x72, 0x6d, 0x5f, 0x70,
+ 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa,
+ 0x42, 0x05, 0x7a, 0x03, 0x18, 0xff, 0x01, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69,
+ 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e,
+ 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73,
+ 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x77,
+ 0x48, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x47, 0x67, 0x69,
+ 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e,
+ 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73,
+ 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74,
+ 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
+ 0x64, 0x12, 0x40, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79,
+ 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 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, 0x0e, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70,
+ 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18,
+ 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x61,
+ 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1c, 0x0a,
+ 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x09, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b,
+ 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
+ 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x52, 0x07, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x42, 0x43, 0x12, 0x48, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79,
+ 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72,
+ 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82,
+ 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x35,
+ 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
+ 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22,
+ 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x5b, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
+ 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,
0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
- 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, 0x64,
- 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x18, 0x09,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77,
- 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x12, 0x6f, 0x0a, 0x1a, 0x64,
- 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, 0x6e,
- 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
- 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61,
- 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73,
- 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75,
- 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f,
- 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x18,
- 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
+ 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74,
+ 0x72, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74,
+ 0x72, 0x79, 0x12, 0x50, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x0c,
- 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e,
- 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x6d,
- 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x69,
- 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10,
- 0x00, 0x42, 0x09, 0x0a, 0x02, 0x75, 0x70, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xcc, 0x02, 0x0a,
- 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46,
- 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x70, 0x5f,
- 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
- 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
- 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65,
- 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x75, 0x70, 0x46,
- 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x16, 0x75, 0x70, 0x5f, 0x66,
+ 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
+ 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74,
+ 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49,
+ 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64,
+ 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+ 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74,
+ 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8a, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72,
+ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74,
+ 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18,
+ 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b,
+ 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d,
+ 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x73, 0x1a, 0x9b, 0x01, 0x0a, 0x07, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43,
+ 0x12, 0x45, 0x0a, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x18, 0x07, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e,
+ 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x47, 0x61, 0x74, 0x65, 0x77,
+ 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x08, 0x67,
+ 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x61, 0x62, 0x73, 0x6f, 0x6c,
+ 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 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, 0x0c, 0x61, 0x62, 0x73, 0x6f,
+ 0x6c, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01,
+ 0x10, 0x01, 0x1a, 0x80, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64,
+ 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x12,
+ 0x4a, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0x64, 0x20, 0x00, 0x52, 0x0b,
+ 0x6d, 0x61, 0x78, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19,
+ 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a,
+ 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+ 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa,
+ 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x59, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41,
+ 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
+ 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f,
+ 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b,
+ 0x73, 0x22, 0xc3, 0x05, 0x0a, 0x19, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12,
+ 0x49, 0x0a, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
+ 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f,
+ 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01,
+ 0x52, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72,
+ 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72,
+ 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10,
+ 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x56, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x74, 0x74,
+ 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70,
+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b,
+ 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61,
+ 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+ 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
+ 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43,
+ 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e,
+ 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+ 0x49, 0x64, 0x73, 0x12, 0x90, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69,
+ 0x6c, 0x65, 0x64, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72,
+ 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f,
+ 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32,
+ 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72,
+ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d,
+ 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2,
+ 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xe6, 0x05, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
+ 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64,
+ 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23,
+ 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
+ 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x25,
+ 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77,
+ 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x43, 0x6e,
+ 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa,
+ 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x5c, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64,
+ 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
+ 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
+ 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64,
+ 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72,
+ 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49,
+ 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77,
+ 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x74, 0x74,
+ 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70,
+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
+ 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x41, 0x74, 0x74,
+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42,
+ 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b,
+ 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61,
+ 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03,
+ 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a,
+ 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e,
+ 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00,
+ 0x22, 0x91, 0x05, 0x0a, 0x22, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65,
+ 0x75, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72,
+ 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0xc8, 0x01, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f,
+ 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19,
+ 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07,
+ 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04,
+ 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74,
+ 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70,
+ 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c,
+ 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65,
+ 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f,
+ 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73,
+ 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64,
+ 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65,
+ 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a,
+ 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79,
+ 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f,
+ 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x46,
+ 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0xd7, 0x01, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64,
+ 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41,
+ 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a,
+ 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65,
+ 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74,
+ 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73,
+ 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73,
+ 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e,
+ 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73,
+ 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65,
+ 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65,
+ 0x73, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64,
+ 0x72, 0x12, 0x3d, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73,
+ 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,
+ 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x13, 0x70, 0x65, 0x6e,
+ 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64,
+ 0x12, 0x32, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x69, 0x6e, 0x5f,
+ 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d,
+ 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74,
+ 0x44, 0x6f, 0x77, 0x6e, 0x22, 0xf8, 0x04, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12,
+ 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74,
+ 0x61, 0x18, 0x02, 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, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74,
+ 0x61, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76,
+ 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74,
+ 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22,
+ 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
+ 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
+ 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8d,
+ 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x74, 0x74, 0x72,
+ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32,
+ 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61,
+ 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d,
+ 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18,
+ 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56,
+ 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+ 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
+ 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22,
+ 0x94, 0x09, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55,
+ 0x70, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
+ 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42,
+ 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65,
+ 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
+ 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e,
+ 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x3b,
+ 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0c, 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,
+ 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x75,
+ 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b,
+ 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5a, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e,
+ 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55,
+ 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x48,
+ 0x00, 0x52, 0x10, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69,
+ 0x7a, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x0b, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65,
+ 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48,
+ 0x00, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x48, 0x0a,
+ 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61,
+ 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e,
+ 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23,
+ 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
+ 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4e,
+ 0x61, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f,
+ 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e,
+ 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48,
+ 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x53, 0x65, 0x6e, 0x74, 0x12,
+ 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c,
+ 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c,
+ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69,
+ 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46,
+ 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23,
+ 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e,
+ 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51,
+ 0x75, 0x65, 0x75, 0x65, 0x64, 0x12, 0x6f, 0x0a, 0x1a, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
+ 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
+ 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f,
+ 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c,
+ 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33,
+ 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74,
+ 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44,
+ 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64,
+ 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65,
+ 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x42, 0x09, 0x0a, 0x02, 0x75,
+ 0x70, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xcc, 0x02, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74,
+ 0x65, 0x72, 0x73, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x70, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
+ 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e,
+ 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f,
+ 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05,
+ 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x75, 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74,
+ 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x16, 0x75, 0x70, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74,
+ 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18, 0x80, 0xc0, 0x02, 0x52, 0x14, 0x75,
+ 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
+ 0x74, 0x65, 0x72, 0x12, 0x51, 0x0a, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d,
+ 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74,
+ 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79,
+ 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa,
+ 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72,
+ 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66,
0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
- 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18,
- 0x80, 0xc0, 0x02, 0x52, 0x14, 0x75, 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72,
- 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x51, 0x0a, 0x0e, 0x64, 0x6f, 0x77,
- 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28,
- 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e,
- 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74,
- 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64,
- 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x18,
- 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70,
- 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09,
- 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18, 0x80, 0xc0, 0x02, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x46,
- 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
- 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xbb, 0x01, 0x0a, 0x14,
- 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69,
- 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74,
- 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e,
- 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
- 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, 0x6e,
- 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x09, 0x64, 0x6f,
- 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e,
- 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41,
- 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
- 0x6e, 0x6b, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x10, 0xa0, 0x8d, 0x06, 0x52, 0x09,
- 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2a, 0xa3, 0x01, 0x0a, 0x10, 0x50, 0x61,
- 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x12,
- 0x0a, 0x0e, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x4e, 0x45,
- 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f,
- 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16,
- 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x5f, 0x53,
- 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d,
- 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4a, 0x41, 0x56, 0x41, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54,
- 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f,
- 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e, 0x45, 0x4c, 0x50, 0x50, 0x10, 0x04, 0x1a, 0x11, 0xea, 0xaa,
- 0x19, 0x0d, 0x18, 0x01, 0x2a, 0x09, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x42,
- 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e,
- 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d,
- 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e,
- 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18,
+ 0x80, 0xc0, 0x02, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74,
+ 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19,
+ 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xbb, 0x01, 0x0a, 0x14, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
+ 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54,
+ 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72,
+ 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63,
+ 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42,
+ 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63,
+ 0x65, 0x49, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b,
+ 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f,
+ 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x0a, 0xfa, 0x42,
+ 0x07, 0x92, 0x01, 0x04, 0x10, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
+ 0x6e, 0x6b, 0x73, 0x2a, 0xa3, 0x01, 0x0a, 0x10, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x4f, 0x52, 0x4d,
+ 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14,
+ 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49,
+ 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54,
+ 0x54, 0x45, 0x52, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45,
+ 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f,
+ 0x4a, 0x41, 0x56, 0x41, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14,
+ 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e,
+ 0x45, 0x4c, 0x50, 0x50, 0x10, 0x04, 0x1a, 0x11, 0xea, 0xaa, 0x19, 0x0d, 0x18, 0x01, 0x2a, 0x09,
+ 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e,
+ 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
+ 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f,
+ 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -2761,7 +3151,7 @@ func file_ttn_lorawan_v3_messages_proto_rawDescGZIP() []byte {
}
var file_ttn_lorawan_v3_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_ttn_lorawan_v3_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
+var file_ttn_lorawan_v3_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 36)
var file_ttn_lorawan_v3_messages_proto_goTypes = []interface{}{
(PayloadFormatter)(0), // 0: ttn.lorawan.v3.PayloadFormatter
(TxAcknowledgment_Result)(0), // 1: ttn.lorawan.v3.TxAcknowledgment.Result
@@ -2785,108 +3175,147 @@ var file_ttn_lorawan_v3_messages_proto_goTypes = []interface{}{
(*MessagePayloadFormatters)(nil), // 19: ttn.lorawan.v3.MessagePayloadFormatters
(*DownlinkQueueRequest)(nil), // 20: ttn.lorawan.v3.DownlinkQueueRequest
nil, // 21: ttn.lorawan.v3.ApplicationUplink.LocationsEntry
- nil, // 22: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry
- nil, // 23: ttn.lorawan.v3.ApplicationLocation.AttributesEntry
- (*ApplicationDownlink_ClassBC)(nil), // 24: ttn.lorawan.v3.ApplicationDownlink.ClassBC
- (*ApplicationDownlink_ConfirmedRetry)(nil), // 25: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry
- (*Message)(nil), // 26: ttn.lorawan.v3.Message
- (*TxSettings)(nil), // 27: ttn.lorawan.v3.TxSettings
- (*RxMetadata)(nil), // 28: ttn.lorawan.v3.RxMetadata
- (*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp
- (*durationpb.Duration)(nil), // 30: google.protobuf.Duration
- (*wrapperspb.BoolValue)(nil), // 31: google.protobuf.BoolValue
- (*EndDeviceIdentifiers)(nil), // 32: ttn.lorawan.v3.EndDeviceIdentifiers
- (*TxRequest)(nil), // 33: ttn.lorawan.v3.TxRequest
- (*GatewayIdentifiers)(nil), // 34: ttn.lorawan.v3.GatewayIdentifiers
- (*wrapperspb.FloatValue)(nil), // 35: google.protobuf.FloatValue
- (*structpb.Struct)(nil), // 36: google.protobuf.Struct
- (*KeyEnvelope)(nil), // 37: ttn.lorawan.v3.KeyEnvelope
- (*EndDeviceVersionIdentifiers)(nil), // 38: ttn.lorawan.v3.EndDeviceVersionIdentifiers
- (*NetworkIdentifiers)(nil), // 39: ttn.lorawan.v3.NetworkIdentifiers
- (*Location)(nil), // 40: ttn.lorawan.v3.Location
- (TxSchedulePriority)(0), // 41: ttn.lorawan.v3.TxSchedulePriority
- (*ErrorDetails)(nil), // 42: ttn.lorawan.v3.ErrorDetails
- (*ClassBCGatewayIdentifiers)(nil), // 43: ttn.lorawan.v3.ClassBCGatewayIdentifiers
- (*wrapperspb.UInt32Value)(nil), // 44: google.protobuf.UInt32Value
+ nil, // 22: ttn.lorawan.v3.ApplicationUplink.AttributesEntry
+ nil, // 23: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry
+ nil, // 24: ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry
+ nil, // 25: ttn.lorawan.v3.ApplicationLocation.AttributesEntry
+ nil, // 26: ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry
+ nil, // 27: ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry
+ (*ApplicationDownlink_ClassBC)(nil), // 28: ttn.lorawan.v3.ApplicationDownlink.ClassBC
+ (*ApplicationDownlink_ConfirmedRetry)(nil), // 29: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry
+ nil, // 30: ttn.lorawan.v3.ApplicationDownlink.LocationsEntry
+ nil, // 31: ttn.lorawan.v3.ApplicationDownlink.AttributesEntry
+ nil, // 32: ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry
+ nil, // 33: ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry
+ nil, // 34: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry
+ nil, // 35: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry
+ nil, // 36: ttn.lorawan.v3.ApplicationServiceData.LocationsEntry
+ nil, // 37: ttn.lorawan.v3.ApplicationServiceData.AttributesEntry
+ (*Message)(nil), // 38: ttn.lorawan.v3.Message
+ (*TxSettings)(nil), // 39: ttn.lorawan.v3.TxSettings
+ (*RxMetadata)(nil), // 40: ttn.lorawan.v3.RxMetadata
+ (*timestamppb.Timestamp)(nil), // 41: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 42: google.protobuf.Duration
+ (*wrapperspb.BoolValue)(nil), // 43: google.protobuf.BoolValue
+ (*EndDeviceIdentifiers)(nil), // 44: ttn.lorawan.v3.EndDeviceIdentifiers
+ (*TxRequest)(nil), // 45: ttn.lorawan.v3.TxRequest
+ (*GatewayIdentifiers)(nil), // 46: ttn.lorawan.v3.GatewayIdentifiers
+ (*wrapperspb.FloatValue)(nil), // 47: google.protobuf.FloatValue
+ (*structpb.Struct)(nil), // 48: google.protobuf.Struct
+ (*KeyEnvelope)(nil), // 49: ttn.lorawan.v3.KeyEnvelope
+ (*EndDeviceVersionIdentifiers)(nil), // 50: ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ (*NetworkIdentifiers)(nil), // 51: ttn.lorawan.v3.NetworkIdentifiers
+ (*Location)(nil), // 52: ttn.lorawan.v3.Location
+ (TxSchedulePriority)(0), // 53: ttn.lorawan.v3.TxSchedulePriority
+ (*ErrorDetails)(nil), // 54: ttn.lorawan.v3.ErrorDetails
+ (*ClassBCGatewayIdentifiers)(nil), // 55: ttn.lorawan.v3.ClassBCGatewayIdentifiers
+ (*wrapperspb.UInt32Value)(nil), // 56: google.protobuf.UInt32Value
}
var file_ttn_lorawan_v3_messages_proto_depIdxs = []int32{
- 26, // 0: ttn.lorawan.v3.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message
- 27, // 1: ttn.lorawan.v3.UplinkMessage.settings:type_name -> ttn.lorawan.v3.TxSettings
- 28, // 2: ttn.lorawan.v3.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
- 29, // 3: ttn.lorawan.v3.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp
- 30, // 4: ttn.lorawan.v3.UplinkMessage.consumed_airtime:type_name -> google.protobuf.Duration
- 31, // 5: ttn.lorawan.v3.UplinkMessage.crc_status:type_name -> google.protobuf.BoolValue
- 26, // 6: ttn.lorawan.v3.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.Message
- 32, // 7: ttn.lorawan.v3.DownlinkMessage.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
- 33, // 8: ttn.lorawan.v3.DownlinkMessage.request:type_name -> ttn.lorawan.v3.TxRequest
- 27, // 9: ttn.lorawan.v3.DownlinkMessage.scheduled:type_name -> ttn.lorawan.v3.TxSettings
+ 38, // 0: ttn.lorawan.v3.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message
+ 39, // 1: ttn.lorawan.v3.UplinkMessage.settings:type_name -> ttn.lorawan.v3.TxSettings
+ 40, // 2: ttn.lorawan.v3.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
+ 41, // 3: ttn.lorawan.v3.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp
+ 42, // 4: ttn.lorawan.v3.UplinkMessage.consumed_airtime:type_name -> google.protobuf.Duration
+ 43, // 5: ttn.lorawan.v3.UplinkMessage.crc_status:type_name -> google.protobuf.BoolValue
+ 38, // 6: ttn.lorawan.v3.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.Message
+ 44, // 7: ttn.lorawan.v3.DownlinkMessage.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
+ 45, // 8: ttn.lorawan.v3.DownlinkMessage.request:type_name -> ttn.lorawan.v3.TxRequest
+ 39, // 9: ttn.lorawan.v3.DownlinkMessage.scheduled:type_name -> ttn.lorawan.v3.TxSettings
1, // 10: ttn.lorawan.v3.TxAcknowledgment.result:type_name -> ttn.lorawan.v3.TxAcknowledgment.Result
3, // 11: ttn.lorawan.v3.TxAcknowledgment.downlink_message:type_name -> ttn.lorawan.v3.DownlinkMessage
- 34, // 12: ttn.lorawan.v3.GatewayTxAcknowledgment.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers
+ 46, // 12: ttn.lorawan.v3.GatewayTxAcknowledgment.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers
4, // 13: ttn.lorawan.v3.GatewayTxAcknowledgment.tx_ack:type_name -> ttn.lorawan.v3.TxAcknowledgment
2, // 14: ttn.lorawan.v3.GatewayUplinkMessage.message:type_name -> ttn.lorawan.v3.UplinkMessage
- 35, // 15: ttn.lorawan.v3.LastBatteryPercentage.value:type_name -> google.protobuf.FloatValue
- 29, // 16: ttn.lorawan.v3.LastBatteryPercentage.received_at:type_name -> google.protobuf.Timestamp
- 36, // 17: ttn.lorawan.v3.ApplicationUplink.decoded_payload:type_name -> google.protobuf.Struct
- 36, // 18: ttn.lorawan.v3.ApplicationUplink.normalized_payload:type_name -> google.protobuf.Struct
- 28, // 19: ttn.lorawan.v3.ApplicationUplink.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
- 27, // 20: ttn.lorawan.v3.ApplicationUplink.settings:type_name -> ttn.lorawan.v3.TxSettings
- 29, // 21: ttn.lorawan.v3.ApplicationUplink.received_at:type_name -> google.protobuf.Timestamp
- 37, // 22: ttn.lorawan.v3.ApplicationUplink.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope
- 30, // 23: ttn.lorawan.v3.ApplicationUplink.consumed_airtime:type_name -> google.protobuf.Duration
+ 47, // 15: ttn.lorawan.v3.LastBatteryPercentage.value:type_name -> google.protobuf.FloatValue
+ 41, // 16: ttn.lorawan.v3.LastBatteryPercentage.received_at:type_name -> google.protobuf.Timestamp
+ 48, // 17: ttn.lorawan.v3.ApplicationUplink.decoded_payload:type_name -> google.protobuf.Struct
+ 48, // 18: ttn.lorawan.v3.ApplicationUplink.normalized_payload:type_name -> google.protobuf.Struct
+ 40, // 19: ttn.lorawan.v3.ApplicationUplink.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
+ 39, // 20: ttn.lorawan.v3.ApplicationUplink.settings:type_name -> ttn.lorawan.v3.TxSettings
+ 41, // 21: ttn.lorawan.v3.ApplicationUplink.received_at:type_name -> google.protobuf.Timestamp
+ 49, // 22: ttn.lorawan.v3.ApplicationUplink.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope
+ 42, // 23: ttn.lorawan.v3.ApplicationUplink.consumed_airtime:type_name -> google.protobuf.Duration
21, // 24: ttn.lorawan.v3.ApplicationUplink.locations:type_name -> ttn.lorawan.v3.ApplicationUplink.LocationsEntry
- 38, // 25: ttn.lorawan.v3.ApplicationUplink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
- 39, // 26: ttn.lorawan.v3.ApplicationUplink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 50, // 25: ttn.lorawan.v3.ApplicationUplink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 26: ttn.lorawan.v3.ApplicationUplink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
7, // 27: ttn.lorawan.v3.ApplicationUplink.last_battery_percentage:type_name -> ttn.lorawan.v3.LastBatteryPercentage
- 36, // 28: ttn.lorawan.v3.ApplicationUplinkNormalized.normalized_payload:type_name -> google.protobuf.Struct
- 28, // 29: ttn.lorawan.v3.ApplicationUplinkNormalized.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
- 27, // 30: ttn.lorawan.v3.ApplicationUplinkNormalized.settings:type_name -> ttn.lorawan.v3.TxSettings
- 29, // 31: ttn.lorawan.v3.ApplicationUplinkNormalized.received_at:type_name -> google.protobuf.Timestamp
- 30, // 32: ttn.lorawan.v3.ApplicationUplinkNormalized.consumed_airtime:type_name -> google.protobuf.Duration
- 22, // 33: ttn.lorawan.v3.ApplicationUplinkNormalized.locations:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry
- 38, // 34: ttn.lorawan.v3.ApplicationUplinkNormalized.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
- 39, // 35: ttn.lorawan.v3.ApplicationUplinkNormalized.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
- 40, // 36: ttn.lorawan.v3.ApplicationLocation.location:type_name -> ttn.lorawan.v3.Location
- 23, // 37: ttn.lorawan.v3.ApplicationLocation.attributes:type_name -> ttn.lorawan.v3.ApplicationLocation.AttributesEntry
- 37, // 38: ttn.lorawan.v3.ApplicationJoinAccept.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope
- 12, // 39: ttn.lorawan.v3.ApplicationJoinAccept.invalidated_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 29, // 40: ttn.lorawan.v3.ApplicationJoinAccept.received_at:type_name -> google.protobuf.Timestamp
- 36, // 41: ttn.lorawan.v3.ApplicationDownlink.decoded_payload:type_name -> google.protobuf.Struct
- 24, // 42: ttn.lorawan.v3.ApplicationDownlink.class_b_c:type_name -> ttn.lorawan.v3.ApplicationDownlink.ClassBC
- 41, // 43: ttn.lorawan.v3.ApplicationDownlink.priority:type_name -> ttn.lorawan.v3.TxSchedulePriority
- 25, // 44: ttn.lorawan.v3.ApplicationDownlink.confirmed_retry:type_name -> ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry
- 12, // 45: ttn.lorawan.v3.ApplicationDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 12, // 46: ttn.lorawan.v3.ApplicationDownlinkFailed.downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 42, // 47: ttn.lorawan.v3.ApplicationDownlinkFailed.error:type_name -> ttn.lorawan.v3.ErrorDetails
- 12, // 48: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 36, // 49: ttn.lorawan.v3.ApplicationServiceData.data:type_name -> google.protobuf.Struct
- 32, // 50: ttn.lorawan.v3.ApplicationUp.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
- 29, // 51: ttn.lorawan.v3.ApplicationUp.received_at:type_name -> google.protobuf.Timestamp
- 8, // 52: ttn.lorawan.v3.ApplicationUp.uplink_message:type_name -> ttn.lorawan.v3.ApplicationUplink
- 9, // 53: ttn.lorawan.v3.ApplicationUp.uplink_normalized:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized
- 11, // 54: ttn.lorawan.v3.ApplicationUp.join_accept:type_name -> ttn.lorawan.v3.ApplicationJoinAccept
- 12, // 55: ttn.lorawan.v3.ApplicationUp.downlink_ack:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 12, // 56: ttn.lorawan.v3.ApplicationUp.downlink_nack:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 12, // 57: ttn.lorawan.v3.ApplicationUp.downlink_sent:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 14, // 58: ttn.lorawan.v3.ApplicationUp.downlink_failed:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed
- 12, // 59: ttn.lorawan.v3.ApplicationUp.downlink_queued:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 15, // 60: ttn.lorawan.v3.ApplicationUp.downlink_queue_invalidated:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks
- 10, // 61: ttn.lorawan.v3.ApplicationUp.location_solved:type_name -> ttn.lorawan.v3.ApplicationLocation
- 17, // 62: ttn.lorawan.v3.ApplicationUp.service_data:type_name -> ttn.lorawan.v3.ApplicationServiceData
- 0, // 63: ttn.lorawan.v3.MessagePayloadFormatters.up_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter
- 0, // 64: ttn.lorawan.v3.MessagePayloadFormatters.down_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter
- 32, // 65: ttn.lorawan.v3.DownlinkQueueRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
- 12, // 66: ttn.lorawan.v3.DownlinkQueueRequest.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
- 40, // 67: ttn.lorawan.v3.ApplicationUplink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
- 40, // 68: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
- 43, // 69: ttn.lorawan.v3.ApplicationDownlink.ClassBC.gateways:type_name -> ttn.lorawan.v3.ClassBCGatewayIdentifiers
- 29, // 70: ttn.lorawan.v3.ApplicationDownlink.ClassBC.absolute_time:type_name -> google.protobuf.Timestamp
- 44, // 71: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry.max_attempts:type_name -> google.protobuf.UInt32Value
- 72, // [72:72] is the sub-list for method output_type
- 72, // [72:72] is the sub-list for method input_type
- 72, // [72:72] is the sub-list for extension type_name
- 72, // [72:72] is the sub-list for extension extendee
- 0, // [0:72] is the sub-list for field type_name
+ 22, // 28: ttn.lorawan.v3.ApplicationUplink.attributes:type_name -> ttn.lorawan.v3.ApplicationUplink.AttributesEntry
+ 48, // 29: ttn.lorawan.v3.ApplicationUplinkNormalized.normalized_payload:type_name -> google.protobuf.Struct
+ 40, // 30: ttn.lorawan.v3.ApplicationUplinkNormalized.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata
+ 39, // 31: ttn.lorawan.v3.ApplicationUplinkNormalized.settings:type_name -> ttn.lorawan.v3.TxSettings
+ 41, // 32: ttn.lorawan.v3.ApplicationUplinkNormalized.received_at:type_name -> google.protobuf.Timestamp
+ 42, // 33: ttn.lorawan.v3.ApplicationUplinkNormalized.consumed_airtime:type_name -> google.protobuf.Duration
+ 23, // 34: ttn.lorawan.v3.ApplicationUplinkNormalized.locations:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry
+ 50, // 35: ttn.lorawan.v3.ApplicationUplinkNormalized.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 36: ttn.lorawan.v3.ApplicationUplinkNormalized.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 24, // 37: ttn.lorawan.v3.ApplicationUplinkNormalized.attributes:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry
+ 52, // 38: ttn.lorawan.v3.ApplicationLocation.location:type_name -> ttn.lorawan.v3.Location
+ 25, // 39: ttn.lorawan.v3.ApplicationLocation.attributes:type_name -> ttn.lorawan.v3.ApplicationLocation.AttributesEntry
+ 49, // 40: ttn.lorawan.v3.ApplicationJoinAccept.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope
+ 12, // 41: ttn.lorawan.v3.ApplicationJoinAccept.invalidated_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 41, // 42: ttn.lorawan.v3.ApplicationJoinAccept.received_at:type_name -> google.protobuf.Timestamp
+ 26, // 43: ttn.lorawan.v3.ApplicationJoinAccept.locations:type_name -> ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry
+ 50, // 44: ttn.lorawan.v3.ApplicationJoinAccept.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 45: ttn.lorawan.v3.ApplicationJoinAccept.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 27, // 46: ttn.lorawan.v3.ApplicationJoinAccept.attributes:type_name -> ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry
+ 48, // 47: ttn.lorawan.v3.ApplicationDownlink.decoded_payload:type_name -> google.protobuf.Struct
+ 28, // 48: ttn.lorawan.v3.ApplicationDownlink.class_b_c:type_name -> ttn.lorawan.v3.ApplicationDownlink.ClassBC
+ 53, // 49: ttn.lorawan.v3.ApplicationDownlink.priority:type_name -> ttn.lorawan.v3.TxSchedulePriority
+ 29, // 50: ttn.lorawan.v3.ApplicationDownlink.confirmed_retry:type_name -> ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry
+ 30, // 51: ttn.lorawan.v3.ApplicationDownlink.locations:type_name -> ttn.lorawan.v3.ApplicationDownlink.LocationsEntry
+ 50, // 52: ttn.lorawan.v3.ApplicationDownlink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 53: ttn.lorawan.v3.ApplicationDownlink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 31, // 54: ttn.lorawan.v3.ApplicationDownlink.attributes:type_name -> ttn.lorawan.v3.ApplicationDownlink.AttributesEntry
+ 12, // 55: ttn.lorawan.v3.ApplicationDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 12, // 56: ttn.lorawan.v3.ApplicationDownlinkFailed.downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 54, // 57: ttn.lorawan.v3.ApplicationDownlinkFailed.error:type_name -> ttn.lorawan.v3.ErrorDetails
+ 32, // 58: ttn.lorawan.v3.ApplicationDownlinkFailed.locations:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry
+ 50, // 59: ttn.lorawan.v3.ApplicationDownlinkFailed.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 60: ttn.lorawan.v3.ApplicationDownlinkFailed.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 33, // 61: ttn.lorawan.v3.ApplicationDownlinkFailed.attributes:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry
+ 12, // 62: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 34, // 63: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.locations:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry
+ 50, // 64: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 65: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 35, // 66: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.attributes:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry
+ 48, // 67: ttn.lorawan.v3.ApplicationServiceData.data:type_name -> google.protobuf.Struct
+ 36, // 68: ttn.lorawan.v3.ApplicationServiceData.locations:type_name -> ttn.lorawan.v3.ApplicationServiceData.LocationsEntry
+ 50, // 69: ttn.lorawan.v3.ApplicationServiceData.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers
+ 51, // 70: ttn.lorawan.v3.ApplicationServiceData.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers
+ 37, // 71: ttn.lorawan.v3.ApplicationServiceData.attributes:type_name -> ttn.lorawan.v3.ApplicationServiceData.AttributesEntry
+ 44, // 72: ttn.lorawan.v3.ApplicationUp.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
+ 41, // 73: ttn.lorawan.v3.ApplicationUp.received_at:type_name -> google.protobuf.Timestamp
+ 8, // 74: ttn.lorawan.v3.ApplicationUp.uplink_message:type_name -> ttn.lorawan.v3.ApplicationUplink
+ 9, // 75: ttn.lorawan.v3.ApplicationUp.uplink_normalized:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized
+ 11, // 76: ttn.lorawan.v3.ApplicationUp.join_accept:type_name -> ttn.lorawan.v3.ApplicationJoinAccept
+ 12, // 77: ttn.lorawan.v3.ApplicationUp.downlink_ack:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 12, // 78: ttn.lorawan.v3.ApplicationUp.downlink_nack:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 12, // 79: ttn.lorawan.v3.ApplicationUp.downlink_sent:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 14, // 80: ttn.lorawan.v3.ApplicationUp.downlink_failed:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed
+ 12, // 81: ttn.lorawan.v3.ApplicationUp.downlink_queued:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 15, // 82: ttn.lorawan.v3.ApplicationUp.downlink_queue_invalidated:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks
+ 10, // 83: ttn.lorawan.v3.ApplicationUp.location_solved:type_name -> ttn.lorawan.v3.ApplicationLocation
+ 17, // 84: ttn.lorawan.v3.ApplicationUp.service_data:type_name -> ttn.lorawan.v3.ApplicationServiceData
+ 0, // 85: ttn.lorawan.v3.MessagePayloadFormatters.up_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter
+ 0, // 86: ttn.lorawan.v3.MessagePayloadFormatters.down_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter
+ 44, // 87: ttn.lorawan.v3.DownlinkQueueRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers
+ 12, // 88: ttn.lorawan.v3.DownlinkQueueRequest.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink
+ 52, // 89: ttn.lorawan.v3.ApplicationUplink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 52, // 90: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 52, // 91: ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 55, // 92: ttn.lorawan.v3.ApplicationDownlink.ClassBC.gateways:type_name -> ttn.lorawan.v3.ClassBCGatewayIdentifiers
+ 41, // 93: ttn.lorawan.v3.ApplicationDownlink.ClassBC.absolute_time:type_name -> google.protobuf.Timestamp
+ 56, // 94: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry.max_attempts:type_name -> google.protobuf.UInt32Value
+ 52, // 95: ttn.lorawan.v3.ApplicationDownlink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 52, // 96: ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 52, // 97: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 52, // 98: ttn.lorawan.v3.ApplicationServiceData.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location
+ 99, // [99:99] is the sub-list for method output_type
+ 99, // [99:99] is the sub-list for method input_type
+ 99, // [99:99] is the sub-list for extension type_name
+ 99, // [99:99] is the sub-list for extension extendee
+ 0, // [0:99] is the sub-list for field type_name
}
func init() { file_ttn_lorawan_v3_messages_proto_init() }
@@ -3128,7 +3557,7 @@ func file_ttn_lorawan_v3_messages_proto_init() {
return nil
}
}
- file_ttn_lorawan_v3_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+ file_ttn_lorawan_v3_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ApplicationDownlink_ClassBC); i {
case 0:
return &v.state
@@ -3140,7 +3569,7 @@ func file_ttn_lorawan_v3_messages_proto_init() {
return nil
}
}
- file_ttn_lorawan_v3_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+ file_ttn_lorawan_v3_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ApplicationDownlink_ConfirmedRetry); i {
case 0:
return &v.state
@@ -3176,7 +3605,7 @@ func file_ttn_lorawan_v3_messages_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_ttn_lorawan_v3_messages_proto_rawDesc,
NumEnums: 2,
- NumMessages: 24,
+ NumMessages: 36,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/pkg/ttnpb/messages.pb.paths.fm.go b/pkg/ttnpb/messages.pb.paths.fm.go
index 0dfa9d1d44..81094e2700 100644
--- a/pkg/ttnpb/messages.pb.paths.fm.go
+++ b/pkg/ttnpb/messages.pb.paths.fm.go
@@ -561,6 +561,7 @@ var ApplicationUplinkFieldPathsNested = []string{
"app_s_key.encrypted_key",
"app_s_key.kek_label",
"app_s_key.key",
+ "attributes",
"confirmed",
"consumed_airtime",
"decoded_payload",
@@ -619,6 +620,7 @@ var ApplicationUplinkFieldPathsNested = []string{
var ApplicationUplinkFieldPathsTopLevel = []string{
"app_s_key",
+ "attributes",
"confirmed",
"consumed_airtime",
"decoded_payload",
@@ -640,6 +642,7 @@ var ApplicationUplinkFieldPathsTopLevel = []string{
"version_ids",
}
var ApplicationUplinkNormalizedFieldPathsNested = []string{
+ "attributes",
"confirmed",
"consumed_airtime",
"f_cnt",
@@ -689,6 +692,7 @@ var ApplicationUplinkNormalizedFieldPathsNested = []string{
}
var ApplicationUplinkNormalizedFieldPathsTopLevel = []string{
+ "attributes",
"confirmed",
"consumed_airtime",
"f_cnt",
@@ -725,20 +729,40 @@ var ApplicationJoinAcceptFieldPathsNested = []string{
"app_s_key.encrypted_key",
"app_s_key.kek_label",
"app_s_key.key",
+ "attributes",
"invalidated_downlinks",
+ "locations",
+ "network_ids",
+ "network_ids.cluster_address",
+ "network_ids.cluster_id",
+ "network_ids.net_id",
+ "network_ids.ns_id",
+ "network_ids.tenant_address",
+ "network_ids.tenant_id",
"pending_session",
"received_at",
"session_key_id",
+ "version_ids",
+ "version_ids.band_id",
+ "version_ids.brand_id",
+ "version_ids.firmware_version",
+ "version_ids.hardware_version",
+ "version_ids.model_id",
}
var ApplicationJoinAcceptFieldPathsTopLevel = []string{
"app_s_key",
+ "attributes",
"invalidated_downlinks",
+ "locations",
+ "network_ids",
"pending_session",
"received_at",
"session_key_id",
+ "version_ids",
}
var ApplicationDownlinkFieldPathsNested = []string{
+ "attributes",
"class_b_c",
"class_b_c.absolute_time",
"class_b_c.gateways",
@@ -752,11 +776,26 @@ var ApplicationDownlinkFieldPathsNested = []string{
"f_cnt",
"f_port",
"frm_payload",
+ "locations",
+ "network_ids",
+ "network_ids.cluster_address",
+ "network_ids.cluster_id",
+ "network_ids.net_id",
+ "network_ids.ns_id",
+ "network_ids.tenant_address",
+ "network_ids.tenant_id",
"priority",
"session_key_id",
+ "version_ids",
+ "version_ids.band_id",
+ "version_ids.brand_id",
+ "version_ids.firmware_version",
+ "version_ids.hardware_version",
+ "version_ids.model_id",
}
var ApplicationDownlinkFieldPathsTopLevel = []string{
+ "attributes",
"class_b_c",
"confirmed",
"confirmed_retry",
@@ -766,8 +805,11 @@ var ApplicationDownlinkFieldPathsTopLevel = []string{
"f_cnt",
"f_port",
"frm_payload",
+ "locations",
+ "network_ids",
"priority",
"session_key_id",
+ "version_ids",
}
var ApplicationDownlinksFieldPathsNested = []string{
"downlinks",
@@ -777,7 +819,9 @@ var ApplicationDownlinksFieldPathsTopLevel = []string{
"downlinks",
}
var ApplicationDownlinkFailedFieldPathsNested = []string{
+ "attributes",
"downlink",
+ "downlink.attributes",
"downlink.class_b_c",
"downlink.class_b_c.absolute_time",
"downlink.class_b_c.gateways",
@@ -791,8 +835,22 @@ var ApplicationDownlinkFailedFieldPathsNested = []string{
"downlink.f_cnt",
"downlink.f_port",
"downlink.frm_payload",
+ "downlink.locations",
+ "downlink.network_ids",
+ "downlink.network_ids.cluster_address",
+ "downlink.network_ids.cluster_id",
+ "downlink.network_ids.net_id",
+ "downlink.network_ids.ns_id",
+ "downlink.network_ids.tenant_address",
+ "downlink.network_ids.tenant_id",
"downlink.priority",
"downlink.session_key_id",
+ "downlink.version_ids",
+ "downlink.version_ids.band_id",
+ "downlink.version_ids.brand_id",
+ "downlink.version_ids.firmware_version",
+ "downlink.version_ids.hardware_version",
+ "downlink.version_ids.model_id",
"error",
"error.attributes",
"error.cause",
@@ -807,22 +865,59 @@ var ApplicationDownlinkFailedFieldPathsNested = []string{
"error.message_format",
"error.name",
"error.namespace",
+ "locations",
+ "network_ids",
+ "network_ids.cluster_address",
+ "network_ids.cluster_id",
+ "network_ids.net_id",
+ "network_ids.ns_id",
+ "network_ids.tenant_address",
+ "network_ids.tenant_id",
+ "version_ids",
+ "version_ids.band_id",
+ "version_ids.brand_id",
+ "version_ids.firmware_version",
+ "version_ids.hardware_version",
+ "version_ids.model_id",
}
var ApplicationDownlinkFailedFieldPathsTopLevel = []string{
+ "attributes",
"downlink",
"error",
+ "locations",
+ "network_ids",
+ "version_ids",
}
var ApplicationInvalidatedDownlinksFieldPathsNested = []string{
+ "attributes",
"downlinks",
"last_f_cnt_down",
+ "locations",
+ "network_ids",
+ "network_ids.cluster_address",
+ "network_ids.cluster_id",
+ "network_ids.net_id",
+ "network_ids.ns_id",
+ "network_ids.tenant_address",
+ "network_ids.tenant_id",
"session_key_id",
+ "version_ids",
+ "version_ids.band_id",
+ "version_ids.brand_id",
+ "version_ids.firmware_version",
+ "version_ids.hardware_version",
+ "version_ids.model_id",
}
var ApplicationInvalidatedDownlinksFieldPathsTopLevel = []string{
+ "attributes",
"downlinks",
"last_f_cnt_down",
+ "locations",
+ "network_ids",
"session_key_id",
+ "version_ids",
}
var DownlinkQueueOperationErrorDetailsFieldPathsNested = []string{
"dev_addr",
@@ -842,13 +937,32 @@ var DownlinkQueueOperationErrorDetailsFieldPathsTopLevel = []string{
"session_key_id",
}
var ApplicationServiceDataFieldPathsNested = []string{
+ "attributes",
"data",
+ "locations",
+ "network_ids",
+ "network_ids.cluster_address",
+ "network_ids.cluster_id",
+ "network_ids.net_id",
+ "network_ids.ns_id",
+ "network_ids.tenant_address",
+ "network_ids.tenant_id",
"service",
+ "version_ids",
+ "version_ids.band_id",
+ "version_ids.brand_id",
+ "version_ids.firmware_version",
+ "version_ids.hardware_version",
+ "version_ids.model_id",
}
var ApplicationServiceDataFieldPathsTopLevel = []string{
+ "attributes",
"data",
+ "locations",
+ "network_ids",
"service",
+ "version_ids",
}
var ApplicationUpFieldPathsNested = []string{
"correlation_ids",
@@ -863,6 +977,7 @@ var ApplicationUpFieldPathsNested = []string{
"simulated",
"up",
"up.downlink_ack",
+ "up.downlink_ack.attributes",
"up.downlink_ack.class_b_c",
"up.downlink_ack.class_b_c.absolute_time",
"up.downlink_ack.class_b_c.gateways",
@@ -876,10 +991,26 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_ack.f_cnt",
"up.downlink_ack.f_port",
"up.downlink_ack.frm_payload",
+ "up.downlink_ack.locations",
+ "up.downlink_ack.network_ids",
+ "up.downlink_ack.network_ids.cluster_address",
+ "up.downlink_ack.network_ids.cluster_id",
+ "up.downlink_ack.network_ids.net_id",
+ "up.downlink_ack.network_ids.ns_id",
+ "up.downlink_ack.network_ids.tenant_address",
+ "up.downlink_ack.network_ids.tenant_id",
"up.downlink_ack.priority",
"up.downlink_ack.session_key_id",
+ "up.downlink_ack.version_ids",
+ "up.downlink_ack.version_ids.band_id",
+ "up.downlink_ack.version_ids.brand_id",
+ "up.downlink_ack.version_ids.firmware_version",
+ "up.downlink_ack.version_ids.hardware_version",
+ "up.downlink_ack.version_ids.model_id",
"up.downlink_failed",
+ "up.downlink_failed.attributes",
"up.downlink_failed.downlink",
+ "up.downlink_failed.downlink.attributes",
"up.downlink_failed.downlink.class_b_c",
"up.downlink_failed.downlink.class_b_c.absolute_time",
"up.downlink_failed.downlink.class_b_c.gateways",
@@ -893,8 +1024,22 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_failed.downlink.f_cnt",
"up.downlink_failed.downlink.f_port",
"up.downlink_failed.downlink.frm_payload",
+ "up.downlink_failed.downlink.locations",
+ "up.downlink_failed.downlink.network_ids",
+ "up.downlink_failed.downlink.network_ids.cluster_address",
+ "up.downlink_failed.downlink.network_ids.cluster_id",
+ "up.downlink_failed.downlink.network_ids.net_id",
+ "up.downlink_failed.downlink.network_ids.ns_id",
+ "up.downlink_failed.downlink.network_ids.tenant_address",
+ "up.downlink_failed.downlink.network_ids.tenant_id",
"up.downlink_failed.downlink.priority",
"up.downlink_failed.downlink.session_key_id",
+ "up.downlink_failed.downlink.version_ids",
+ "up.downlink_failed.downlink.version_ids.band_id",
+ "up.downlink_failed.downlink.version_ids.brand_id",
+ "up.downlink_failed.downlink.version_ids.firmware_version",
+ "up.downlink_failed.downlink.version_ids.hardware_version",
+ "up.downlink_failed.downlink.version_ids.model_id",
"up.downlink_failed.error",
"up.downlink_failed.error.attributes",
"up.downlink_failed.error.cause",
@@ -909,7 +1054,22 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_failed.error.message_format",
"up.downlink_failed.error.name",
"up.downlink_failed.error.namespace",
+ "up.downlink_failed.locations",
+ "up.downlink_failed.network_ids",
+ "up.downlink_failed.network_ids.cluster_address",
+ "up.downlink_failed.network_ids.cluster_id",
+ "up.downlink_failed.network_ids.net_id",
+ "up.downlink_failed.network_ids.ns_id",
+ "up.downlink_failed.network_ids.tenant_address",
+ "up.downlink_failed.network_ids.tenant_id",
+ "up.downlink_failed.version_ids",
+ "up.downlink_failed.version_ids.band_id",
+ "up.downlink_failed.version_ids.brand_id",
+ "up.downlink_failed.version_ids.firmware_version",
+ "up.downlink_failed.version_ids.hardware_version",
+ "up.downlink_failed.version_ids.model_id",
"up.downlink_nack",
+ "up.downlink_nack.attributes",
"up.downlink_nack.class_b_c",
"up.downlink_nack.class_b_c.absolute_time",
"up.downlink_nack.class_b_c.gateways",
@@ -923,13 +1083,43 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_nack.f_cnt",
"up.downlink_nack.f_port",
"up.downlink_nack.frm_payload",
+ "up.downlink_nack.locations",
+ "up.downlink_nack.network_ids",
+ "up.downlink_nack.network_ids.cluster_address",
+ "up.downlink_nack.network_ids.cluster_id",
+ "up.downlink_nack.network_ids.net_id",
+ "up.downlink_nack.network_ids.ns_id",
+ "up.downlink_nack.network_ids.tenant_address",
+ "up.downlink_nack.network_ids.tenant_id",
"up.downlink_nack.priority",
"up.downlink_nack.session_key_id",
+ "up.downlink_nack.version_ids",
+ "up.downlink_nack.version_ids.band_id",
+ "up.downlink_nack.version_ids.brand_id",
+ "up.downlink_nack.version_ids.firmware_version",
+ "up.downlink_nack.version_ids.hardware_version",
+ "up.downlink_nack.version_ids.model_id",
"up.downlink_queue_invalidated",
+ "up.downlink_queue_invalidated.attributes",
"up.downlink_queue_invalidated.downlinks",
"up.downlink_queue_invalidated.last_f_cnt_down",
+ "up.downlink_queue_invalidated.locations",
+ "up.downlink_queue_invalidated.network_ids",
+ "up.downlink_queue_invalidated.network_ids.cluster_address",
+ "up.downlink_queue_invalidated.network_ids.cluster_id",
+ "up.downlink_queue_invalidated.network_ids.net_id",
+ "up.downlink_queue_invalidated.network_ids.ns_id",
+ "up.downlink_queue_invalidated.network_ids.tenant_address",
+ "up.downlink_queue_invalidated.network_ids.tenant_id",
"up.downlink_queue_invalidated.session_key_id",
+ "up.downlink_queue_invalidated.version_ids",
+ "up.downlink_queue_invalidated.version_ids.band_id",
+ "up.downlink_queue_invalidated.version_ids.brand_id",
+ "up.downlink_queue_invalidated.version_ids.firmware_version",
+ "up.downlink_queue_invalidated.version_ids.hardware_version",
+ "up.downlink_queue_invalidated.version_ids.model_id",
"up.downlink_queued",
+ "up.downlink_queued.attributes",
"up.downlink_queued.class_b_c",
"up.downlink_queued.class_b_c.absolute_time",
"up.downlink_queued.class_b_c.gateways",
@@ -943,9 +1133,24 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_queued.f_cnt",
"up.downlink_queued.f_port",
"up.downlink_queued.frm_payload",
+ "up.downlink_queued.locations",
+ "up.downlink_queued.network_ids",
+ "up.downlink_queued.network_ids.cluster_address",
+ "up.downlink_queued.network_ids.cluster_id",
+ "up.downlink_queued.network_ids.net_id",
+ "up.downlink_queued.network_ids.ns_id",
+ "up.downlink_queued.network_ids.tenant_address",
+ "up.downlink_queued.network_ids.tenant_id",
"up.downlink_queued.priority",
"up.downlink_queued.session_key_id",
+ "up.downlink_queued.version_ids",
+ "up.downlink_queued.version_ids.band_id",
+ "up.downlink_queued.version_ids.brand_id",
+ "up.downlink_queued.version_ids.firmware_version",
+ "up.downlink_queued.version_ids.hardware_version",
+ "up.downlink_queued.version_ids.model_id",
"up.downlink_sent",
+ "up.downlink_sent.attributes",
"up.downlink_sent.class_b_c",
"up.downlink_sent.class_b_c.absolute_time",
"up.downlink_sent.class_b_c.gateways",
@@ -959,17 +1164,46 @@ var ApplicationUpFieldPathsNested = []string{
"up.downlink_sent.f_cnt",
"up.downlink_sent.f_port",
"up.downlink_sent.frm_payload",
+ "up.downlink_sent.locations",
+ "up.downlink_sent.network_ids",
+ "up.downlink_sent.network_ids.cluster_address",
+ "up.downlink_sent.network_ids.cluster_id",
+ "up.downlink_sent.network_ids.net_id",
+ "up.downlink_sent.network_ids.ns_id",
+ "up.downlink_sent.network_ids.tenant_address",
+ "up.downlink_sent.network_ids.tenant_id",
"up.downlink_sent.priority",
"up.downlink_sent.session_key_id",
+ "up.downlink_sent.version_ids",
+ "up.downlink_sent.version_ids.band_id",
+ "up.downlink_sent.version_ids.brand_id",
+ "up.downlink_sent.version_ids.firmware_version",
+ "up.downlink_sent.version_ids.hardware_version",
+ "up.downlink_sent.version_ids.model_id",
"up.join_accept",
"up.join_accept.app_s_key",
"up.join_accept.app_s_key.encrypted_key",
"up.join_accept.app_s_key.kek_label",
"up.join_accept.app_s_key.key",
+ "up.join_accept.attributes",
"up.join_accept.invalidated_downlinks",
+ "up.join_accept.locations",
+ "up.join_accept.network_ids",
+ "up.join_accept.network_ids.cluster_address",
+ "up.join_accept.network_ids.cluster_id",
+ "up.join_accept.network_ids.net_id",
+ "up.join_accept.network_ids.ns_id",
+ "up.join_accept.network_ids.tenant_address",
+ "up.join_accept.network_ids.tenant_id",
"up.join_accept.pending_session",
"up.join_accept.received_at",
"up.join_accept.session_key_id",
+ "up.join_accept.version_ids",
+ "up.join_accept.version_ids.band_id",
+ "up.join_accept.version_ids.brand_id",
+ "up.join_accept.version_ids.firmware_version",
+ "up.join_accept.version_ids.hardware_version",
+ "up.join_accept.version_ids.model_id",
"up.location_solved",
"up.location_solved.attributes",
"up.location_solved.location",
@@ -980,13 +1214,29 @@ var ApplicationUpFieldPathsNested = []string{
"up.location_solved.location.source",
"up.location_solved.service",
"up.service_data",
+ "up.service_data.attributes",
"up.service_data.data",
+ "up.service_data.locations",
+ "up.service_data.network_ids",
+ "up.service_data.network_ids.cluster_address",
+ "up.service_data.network_ids.cluster_id",
+ "up.service_data.network_ids.net_id",
+ "up.service_data.network_ids.ns_id",
+ "up.service_data.network_ids.tenant_address",
+ "up.service_data.network_ids.tenant_id",
"up.service_data.service",
+ "up.service_data.version_ids",
+ "up.service_data.version_ids.band_id",
+ "up.service_data.version_ids.brand_id",
+ "up.service_data.version_ids.firmware_version",
+ "up.service_data.version_ids.hardware_version",
+ "up.service_data.version_ids.model_id",
"up.uplink_message",
"up.uplink_message.app_s_key",
"up.uplink_message.app_s_key.encrypted_key",
"up.uplink_message.app_s_key.kek_label",
"up.uplink_message.app_s_key.key",
+ "up.uplink_message.attributes",
"up.uplink_message.confirmed",
"up.uplink_message.consumed_airtime",
"up.uplink_message.decoded_payload",
@@ -1042,6 +1292,7 @@ var ApplicationUpFieldPathsNested = []string{
"up.uplink_message.version_ids.hardware_version",
"up.uplink_message.version_ids.model_id",
"up.uplink_normalized",
+ "up.uplink_normalized.attributes",
"up.uplink_normalized.confirmed",
"up.uplink_normalized.consumed_airtime",
"up.uplink_normalized.f_cnt",
diff --git a/pkg/ttnpb/messages.pb.setters.fm.go b/pkg/ttnpb/messages.pb.setters.fm.go
index 8cfbcff174..ad7dc055f6 100644
--- a/pkg/ttnpb/messages.pb.setters.fm.go
+++ b/pkg/ttnpb/messages.pb.setters.fm.go
@@ -778,6 +778,15 @@ func (dst *ApplicationUplink) SetFields(src *ApplicationUplink, paths ...string)
dst.LastBatteryPercentage = nil
}
}
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -966,6 +975,15 @@ func (dst *ApplicationUplinkNormalized) SetFields(src *ApplicationUplinkNormaliz
dst.NetworkIds = nil
}
}
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -1094,6 +1112,74 @@ func (dst *ApplicationJoinAccept) SetFields(src *ApplicationJoinAccept, paths ..
} else {
dst.ReceivedAt = nil
}
+ case "locations":
+ if len(subs) > 0 {
+ return fmt.Errorf("'locations' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Locations = src.Locations
+ } else {
+ dst.Locations = nil
+ }
+ case "version_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *EndDeviceVersionIdentifiers
+ if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.VersionIds
+ }
+ if dst.VersionIds != nil {
+ newDst = dst.VersionIds
+ } else {
+ newDst = &EndDeviceVersionIdentifiers{}
+ dst.VersionIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.VersionIds = src.VersionIds
+ } else {
+ dst.VersionIds = nil
+ }
+ }
+ case "network_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *NetworkIdentifiers
+ if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.NetworkIds
+ }
+ if dst.NetworkIds != nil {
+ newDst = dst.NetworkIds
+ } else {
+ newDst = &NetworkIdentifiers{}
+ dst.NetworkIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.NetworkIds = src.NetworkIds
+ } else {
+ dst.NetworkIds = nil
+ }
+ }
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -1239,6 +1325,74 @@ func (dst *ApplicationDownlink) SetFields(src *ApplicationDownlink, paths ...str
dst.ConfirmedRetry = nil
}
}
+ case "locations":
+ if len(subs) > 0 {
+ return fmt.Errorf("'locations' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Locations = src.Locations
+ } else {
+ dst.Locations = nil
+ }
+ case "version_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *EndDeviceVersionIdentifiers
+ if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.VersionIds
+ }
+ if dst.VersionIds != nil {
+ newDst = dst.VersionIds
+ } else {
+ newDst = &EndDeviceVersionIdentifiers{}
+ dst.VersionIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.VersionIds = src.VersionIds
+ } else {
+ dst.VersionIds = nil
+ }
+ }
+ case "network_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *NetworkIdentifiers
+ if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.NetworkIds
+ }
+ if dst.NetworkIds != nil {
+ newDst = dst.NetworkIds
+ } else {
+ newDst = &NetworkIdentifiers{}
+ dst.NetworkIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.NetworkIds = src.NetworkIds
+ } else {
+ dst.NetworkIds = nil
+ }
+ }
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -1320,6 +1474,74 @@ func (dst *ApplicationDownlinkFailed) SetFields(src *ApplicationDownlinkFailed,
dst.Error = nil
}
}
+ case "locations":
+ if len(subs) > 0 {
+ return fmt.Errorf("'locations' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Locations = src.Locations
+ } else {
+ dst.Locations = nil
+ }
+ case "version_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *EndDeviceVersionIdentifiers
+ if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.VersionIds
+ }
+ if dst.VersionIds != nil {
+ newDst = dst.VersionIds
+ } else {
+ newDst = &EndDeviceVersionIdentifiers{}
+ dst.VersionIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.VersionIds = src.VersionIds
+ } else {
+ dst.VersionIds = nil
+ }
+ }
+ case "network_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *NetworkIdentifiers
+ if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.NetworkIds
+ }
+ if dst.NetworkIds != nil {
+ newDst = dst.NetworkIds
+ } else {
+ newDst = &NetworkIdentifiers{}
+ dst.NetworkIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.NetworkIds = src.NetworkIds
+ } else {
+ dst.NetworkIds = nil
+ }
+ }
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -1359,6 +1581,74 @@ func (dst *ApplicationInvalidatedDownlinks) SetFields(src *ApplicationInvalidate
} else {
dst.SessionKeyId = nil
}
+ case "locations":
+ if len(subs) > 0 {
+ return fmt.Errorf("'locations' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Locations = src.Locations
+ } else {
+ dst.Locations = nil
+ }
+ case "version_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *EndDeviceVersionIdentifiers
+ if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.VersionIds
+ }
+ if dst.VersionIds != nil {
+ newDst = dst.VersionIds
+ } else {
+ newDst = &EndDeviceVersionIdentifiers{}
+ dst.VersionIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.VersionIds = src.VersionIds
+ } else {
+ dst.VersionIds = nil
+ }
+ }
+ case "network_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *NetworkIdentifiers
+ if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.NetworkIds
+ }
+ if dst.NetworkIds != nil {
+ newDst = dst.NetworkIds
+ } else {
+ newDst = &NetworkIdentifiers{}
+ dst.NetworkIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.NetworkIds = src.NetworkIds
+ } else {
+ dst.NetworkIds = nil
+ }
+ }
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
@@ -1456,6 +1746,74 @@ func (dst *ApplicationServiceData) SetFields(src *ApplicationServiceData, paths
} else {
dst.Data = nil
}
+ case "locations":
+ if len(subs) > 0 {
+ return fmt.Errorf("'locations' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Locations = src.Locations
+ } else {
+ dst.Locations = nil
+ }
+ case "version_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *EndDeviceVersionIdentifiers
+ if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.VersionIds
+ }
+ if dst.VersionIds != nil {
+ newDst = dst.VersionIds
+ } else {
+ newDst = &EndDeviceVersionIdentifiers{}
+ dst.VersionIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.VersionIds = src.VersionIds
+ } else {
+ dst.VersionIds = nil
+ }
+ }
+ case "network_ids":
+ if len(subs) > 0 {
+ var newDst, newSrc *NetworkIdentifiers
+ if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil {
+ continue
+ }
+ if src != nil {
+ newSrc = src.NetworkIds
+ }
+ if dst.NetworkIds != nil {
+ newDst = dst.NetworkIds
+ } else {
+ newDst = &NetworkIdentifiers{}
+ dst.NetworkIds = newDst
+ }
+ if err := newDst.SetFields(newSrc, subs...); err != nil {
+ return err
+ }
+ } else {
+ if src != nil {
+ dst.NetworkIds = src.NetworkIds
+ } else {
+ dst.NetworkIds = nil
+ }
+ }
+ case "attributes":
+ if len(subs) > 0 {
+ return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.Attributes = src.Attributes
+ } else {
+ dst.Attributes = nil
+ }
default:
return fmt.Errorf("invalid field: '%s'", name)
diff --git a/pkg/ttnpb/messages.pb.validate.go b/pkg/ttnpb/messages.pb.validate.go
index e12c1ee3fd..6d13b82dd1 100644
--- a/pkg/ttnpb/messages.pb.validate.go
+++ b/pkg/ttnpb/messages.pb.validate.go
@@ -1036,6 +1036,41 @@ func (m *ApplicationUplink) ValidateFields(paths ...string) error {
}
}
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationUplinkValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationUplinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationUplink_Attributes_Pattern.MatchString(key) {
+ return ApplicationUplinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationUplinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationUplinkValidationError{
field: name,
@@ -1106,6 +1141,8 @@ var _ApplicationUplink_FPort_NotInLookup = map[uint32]struct{}{
224: {},
}
+var _ApplicationUplink_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationUplinkNormalized with
// the rules defined in the proto definition for this message. If any rules
// are violated, an error is returned.
@@ -1273,6 +1310,41 @@ func (m *ApplicationUplinkNormalized) ValidateFields(paths ...string) error {
}
}
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationUplinkNormalizedValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationUplinkNormalizedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationUplinkNormalized_Attributes_Pattern.MatchString(key) {
+ return ApplicationUplinkNormalizedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationUplinkNormalizedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationUplinkNormalizedValidationError{
field: name,
@@ -1344,6 +1416,8 @@ var _ApplicationUplinkNormalized_FPort_NotInLookup = map[uint32]struct{}{
224: {},
}
+var _ApplicationUplinkNormalized_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationLocation with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
@@ -1547,6 +1621,84 @@ func (m *ApplicationJoinAccept) ValidateFields(paths ...string) error {
}
}
+ case "locations":
+
+ for key, val := range m.GetLocations() {
+ _ = val
+
+ // no validation rules for Locations[key]
+
+ if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationJoinAcceptValidationError{
+ field: fmt.Sprintf("locations[%v]", key),
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ }
+
+ case "version_ids":
+
+ if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationJoinAcceptValidationError{
+ field: "version_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "network_ids":
+
+ if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationJoinAcceptValidationError{
+ field: "network_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationJoinAcceptValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationJoinAcceptValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationJoinAccept_Attributes_Pattern.MatchString(key) {
+ return ApplicationJoinAcceptValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationJoinAcceptValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationJoinAcceptValidationError{
field: name,
@@ -1613,6 +1765,8 @@ var _ interface {
ErrorName() string
} = ApplicationJoinAcceptValidationError{}
+var _ApplicationJoinAccept_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationDownlink with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
@@ -1727,6 +1881,84 @@ func (m *ApplicationDownlink) ValidateFields(paths ...string) error {
}
}
+ case "locations":
+
+ for key, val := range m.GetLocations() {
+ _ = val
+
+ // no validation rules for Locations[key]
+
+ if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkValidationError{
+ field: fmt.Sprintf("locations[%v]", key),
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ }
+
+ case "version_ids":
+
+ if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkValidationError{
+ field: "version_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "network_ids":
+
+ if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkValidationError{
+ field: "network_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationDownlinkValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationDownlinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationDownlink_Attributes_Pattern.MatchString(key) {
+ return ApplicationDownlinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationDownlinkValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationDownlinkValidationError{
field: name,
@@ -1797,6 +2029,8 @@ var _ApplicationDownlink_FPort_NotInLookup = map[uint32]struct{}{
224: {},
}
+var _ApplicationDownlink_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationDownlinks with the
// rules defined in the proto definition for this message. If any rules are
// violated, an error is returned.
@@ -1948,6 +2182,84 @@ func (m *ApplicationDownlinkFailed) ValidateFields(paths ...string) error {
}
}
+ case "locations":
+
+ for key, val := range m.GetLocations() {
+ _ = val
+
+ // no validation rules for Locations[key]
+
+ if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkFailedValidationError{
+ field: fmt.Sprintf("locations[%v]", key),
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ }
+
+ case "version_ids":
+
+ if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkFailedValidationError{
+ field: "version_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "network_ids":
+
+ if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationDownlinkFailedValidationError{
+ field: "network_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationDownlinkFailedValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationDownlinkFailedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationDownlinkFailed_Attributes_Pattern.MatchString(key) {
+ return ApplicationDownlinkFailedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationDownlinkFailedValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationDownlinkFailedValidationError{
field: name,
@@ -2015,6 +2327,8 @@ var _ interface {
ErrorName() string
} = ApplicationDownlinkFailedValidationError{}
+var _ApplicationDownlinkFailed_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationInvalidatedDownlinks
// with the rules defined in the proto definition for this message. If any
// rules are violated, an error is returned.
@@ -2058,6 +2372,84 @@ func (m *ApplicationInvalidatedDownlinks) ValidateFields(paths ...string) error
}
}
+ case "locations":
+
+ for key, val := range m.GetLocations() {
+ _ = val
+
+ // no validation rules for Locations[key]
+
+ if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: fmt.Sprintf("locations[%v]", key),
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ }
+
+ case "version_ids":
+
+ if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: "version_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "network_ids":
+
+ if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: "network_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationInvalidatedDownlinks_Attributes_Pattern.MatchString(key) {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationInvalidatedDownlinksValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationInvalidatedDownlinksValidationError{
field: name,
@@ -2125,6 +2517,8 @@ var _ interface {
ErrorName() string
} = ApplicationInvalidatedDownlinksValidationError{}
+var _ApplicationInvalidatedDownlinks_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on DownlinkQueueOperationErrorDetails
// with the rules defined in the proto definition for this message. If any
// rules are violated, an error is returned.
@@ -2284,6 +2678,84 @@ func (m *ApplicationServiceData) ValidateFields(paths ...string) error {
}
}
+ case "locations":
+
+ for key, val := range m.GetLocations() {
+ _ = val
+
+ // no validation rules for Locations[key]
+
+ if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationServiceDataValidationError{
+ field: fmt.Sprintf("locations[%v]", key),
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ }
+
+ case "version_ids":
+
+ if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationServiceDataValidationError{
+ field: "version_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "network_ids":
+
+ if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok {
+ if err := v.ValidateFields(subs...); err != nil {
+ return ApplicationServiceDataValidationError{
+ field: "network_ids",
+ reason: "embedded message failed validation",
+ cause: err,
+ }
+ }
+ }
+
+ case "attributes":
+
+ if len(m.GetAttributes()) > 10 {
+ return ApplicationServiceDataValidationError{
+ field: "attributes",
+ reason: "value must contain no more than 10 pair(s)",
+ }
+ }
+
+ for key, val := range m.GetAttributes() {
+ _ = val
+
+ if utf8.RuneCountInString(key) > 36 {
+ return ApplicationServiceDataValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 36 runes",
+ }
+ }
+
+ if !_ApplicationServiceData_Attributes_Pattern.MatchString(key) {
+ return ApplicationServiceDataValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"",
+ }
+ }
+
+ if utf8.RuneCountInString(val) > 200 {
+ return ApplicationServiceDataValidationError{
+ field: fmt.Sprintf("attributes[%v]", key),
+ reason: "value length must be at most 200 runes",
+ }
+ }
+
+ }
+
default:
return ApplicationServiceDataValidationError{
field: name,
@@ -2350,6 +2822,8 @@ var _ interface {
ErrorName() string
} = ApplicationServiceDataValidationError{}
+var _ApplicationServiceData_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$")
+
// ValidateFields checks the field values on ApplicationUp with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
diff --git a/pkg/ttnpb/messages_flags.pb.go b/pkg/ttnpb/messages_flags.pb.go
index ead7ad98e1..80f01568ec 100644
--- a/pkg/ttnpb/messages_flags.pb.go
+++ b/pkg/ttnpb/messages_flags.pb.go
@@ -40,6 +40,7 @@ func AddSelectFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hid
AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-battery-percentage", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-battery-percentage", prefix), true), flagsplugin.WithHidden(hidden)))
// NOTE: last_battery_percentage (LastBatteryPercentage) does not seem to have select flags.
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationUplink message from select flags.
@@ -165,6 +166,11 @@ func PathsFromSelectFlagsForApplicationUplink(flags *pflag.FlagSet, prefix strin
paths = append(paths, flagsplugin.Prefix("last_battery_percentage", prefix))
}
// NOTE: last_battery_percentage (LastBatteryPercentage) does not seem to have select flags.
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -190,6 +196,7 @@ func AddSetFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hidden
AddSetFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
AddSetFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
// FIXME: Skipping LastBatteryPercentage because it does not seem to implement AddSetFlags.
+ flags.AddFlag(flagsplugin.NewStringStringMapFlag(flagsplugin.Prefix("attributes", prefix), "", flagsplugin.WithHidden(hidden)))
}
// SetFromFlags sets the ApplicationUplink message from flags.
@@ -305,6 +312,12 @@ func (m *ApplicationUplink) SetFromFlags(flags *pflag.FlagSet, prefix string) (p
}
}
// FIXME: Skipping LastBatteryPercentage because it does not seem to implement AddSetFlags.
+ if val, changed, err := flagsplugin.GetStringStringMap(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if changed {
+ m.Attributes = val
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -327,6 +340,7 @@ func AddSelectFlagsForApplicationUplinkNormalized(flags *pflag.FlagSet, prefix s
AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationUplinkNormalized message from select flags.
@@ -416,6 +430,11 @@ func PathsFromSelectFlagsForApplicationUplinkNormalized(flags *pflag.FlagSet, pr
} else {
paths = append(paths, selectPaths...)
}
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -460,6 +479,12 @@ func AddSelectFlagsForApplicationJoinAccept(flags *pflag.FlagSet, prefix string,
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("invalidated-downlinks", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("invalidated-downlinks", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("pending-session", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("pending-session", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("received-at", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("received-at", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationJoinAccept message from select flags.
@@ -494,6 +519,36 @@ func PathsFromSelectFlagsForApplicationJoinAccept(flags *pflag.FlagSet, prefix s
} else if selected && val {
paths = append(paths, flagsplugin.Prefix("received_at", prefix))
}
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("locations", prefix))
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("version_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("network_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -595,6 +650,12 @@ func AddSelectFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix string, h
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("correlation-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("correlation-ids", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("confirmed-retry", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("confirmed-retry", prefix), true), flagsplugin.WithHidden(hidden)))
AddSelectFlagsForApplicationDownlink_ConfirmedRetry(flags, flagsplugin.Prefix("confirmed-retry", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationDownlink message from select flags.
@@ -664,6 +725,36 @@ func PathsFromSelectFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix str
} else {
paths = append(paths, selectPaths...)
}
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("locations", prefix))
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("version_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("network_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -680,6 +771,10 @@ func AddSetFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix string, hidd
flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("priority", prefix), flagsplugin.EnumValueDesc(TxSchedulePriority_value), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewStringSliceFlag(flagsplugin.Prefix("correlation-ids", prefix), "", flagsplugin.WithHidden(hidden)))
AddSetFlagsForApplicationDownlink_ConfirmedRetry(flags, flagsplugin.Prefix("confirmed-retry", prefix), hidden)
+ // FIXME: Skipping Locations because maps with message value types are currently not supported.
+ AddSetFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ AddSetFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewStringStringMapFlag(flagsplugin.Prefix("attributes", prefix), "", flagsplugin.WithHidden(hidden)))
}
// SetFromFlags sets the ApplicationDownlink message from flags.
@@ -757,6 +852,33 @@ func (m *ApplicationDownlink) SetFromFlags(flags *pflag.FlagSet, prefix string)
paths = append(paths, setPaths...)
}
}
+ // FIXME: Skipping Locations because maps with message value types are currently not supported.
+ if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("version_ids", prefix)); changed {
+ if m.VersionIds == nil {
+ m.VersionIds = &EndDeviceVersionIdentifiers{}
+ }
+ if setPaths, err := m.VersionIds.SetFromFlags(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, setPaths...)
+ }
+ }
+ if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("network_ids", prefix)); changed {
+ if m.NetworkIds == nil {
+ m.NetworkIds = &NetworkIdentifiers{}
+ }
+ if setPaths, err := m.NetworkIds.SetFromFlags(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, setPaths...)
+ }
+ }
+ if val, changed, err := flagsplugin.GetStringStringMap(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if changed {
+ m.Attributes = val
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -766,6 +888,12 @@ func AddSelectFlagsForApplicationDownlinkFailed(flags *pflag.FlagSet, prefix str
AddSelectFlagsForApplicationDownlink(flags, flagsplugin.Prefix("downlink", prefix), hidden)
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("error", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("error", prefix), true), flagsplugin.WithHidden(hidden)))
// NOTE: error (ErrorDetails) does not seem to have select flags.
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationDownlinkFailed message from select flags.
@@ -786,6 +914,36 @@ func PathsFromSelectFlagsForApplicationDownlinkFailed(flags *pflag.FlagSet, pref
paths = append(paths, flagsplugin.Prefix("error", prefix))
}
// NOTE: error (ErrorDetails) does not seem to have select flags.
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("locations", prefix))
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("version_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("network_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -794,6 +952,12 @@ func AddSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet, pref
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("downlinks", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("downlinks", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-f-cnt-down", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-f-cnt-down", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("session-key-id", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("session-key-id", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationInvalidatedDownlinks message from select flags.
@@ -813,6 +977,36 @@ func PathsFromSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet
} else if selected && val {
paths = append(paths, flagsplugin.Prefix("session_key_id", prefix))
}
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("locations", prefix))
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("version_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("network_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
@@ -820,6 +1014,12 @@ func PathsFromSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet
func AddSelectFlagsForApplicationServiceData(flags *pflag.FlagSet, prefix string, hidden bool) {
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("service", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("service", prefix), false), flagsplugin.WithHidden(hidden)))
flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("data", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("data", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden)))
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden)))
+ AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden)
+ flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden)))
}
// SelectFromFlags outputs the fieldmask paths forApplicationServiceData message from select flags.
@@ -834,6 +1034,36 @@ func PathsFromSelectFlagsForApplicationServiceData(flags *pflag.FlagSet, prefix
} else if selected && val {
paths = append(paths, flagsplugin.Prefix("data", prefix))
}
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("locations", prefix))
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("version_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("network_ids", prefix))
+ }
+ if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil {
+ return nil, err
+ } else {
+ paths = append(paths, selectPaths...)
+ }
+ if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil {
+ return nil, err
+ } else if selected && val {
+ paths = append(paths, flagsplugin.Prefix("attributes", prefix))
+ }
return paths, nil
}
diff --git a/pkg/ttnpb/messages_json.pb.go b/pkg/ttnpb/messages_json.pb.go
index d73f3c4f35..8fdbb15b89 100644
--- a/pkg/ttnpb/messages_json.pb.go
+++ b/pkg/ttnpb/messages_json.pb.go
@@ -725,6 +725,18 @@ func (x *ApplicationUplink) MarshalProtoJSON(s *jsonplugin.MarshalState) {
// NOTE: LastBatteryPercentage does not seem to implement MarshalProtoJSON.
golang.MarshalMessage(s, x.LastBatteryPercentage)
}
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -897,6 +909,16 @@ func (x *ApplicationUplink) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) {
var v LastBatteryPercentage
golang.UnmarshalMessage(s, &v)
x.LastBatteryPercentage = &v
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1011,6 +1033,18 @@ func (x *ApplicationUplinkNormalized) MarshalProtoJSON(s *jsonplugin.MarshalStat
s.WriteObjectField("network_ids")
x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
}
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -1140,6 +1174,16 @@ func (x *ApplicationUplinkNormalized) UnmarshalProtoJSON(s *jsonplugin.Unmarshal
}
x.NetworkIds = &NetworkIdentifiers{}
x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1268,6 +1312,41 @@ func (x *ApplicationJoinAccept) MarshalProtoJSON(s *jsonplugin.MarshalState) {
golang.MarshalTimestamp(s, x.ReceivedAt)
}
}
+ if x.Locations != nil || s.HasField("locations") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("locations")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Locations {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ v.MarshalProtoJSON(s.WithField("locations"))
+ }
+ s.WriteObjectEnd()
+ }
+ if x.VersionIds != nil || s.HasField("version_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("version_ids")
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON.
+ golang.MarshalMessage(s, x.VersionIds)
+ }
+ if x.NetworkIds != nil || s.HasField("network_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("network_ids")
+ x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
+ }
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -1327,6 +1406,45 @@ func (x *ApplicationJoinAccept) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState)
return
}
x.ReceivedAt = v
+ case "locations":
+ s.AddField("locations")
+ if s.ReadNil() {
+ x.Locations = nil
+ return
+ }
+ x.Locations = make(map[string]*Location)
+ s.ReadStringMap(func(key string) {
+ var v Location
+ v.UnmarshalProtoJSON(s)
+ x.Locations[key] = &v
+ })
+ case "version_ids", "versionIds":
+ s.AddField("version_ids")
+ if s.ReadNil() {
+ x.VersionIds = nil
+ return
+ }
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON.
+ var v EndDeviceVersionIdentifiers
+ golang.UnmarshalMessage(s, &v)
+ x.VersionIds = &v
+ case "network_ids", "networkIds":
+ if s.ReadNil() {
+ x.NetworkIds = nil
+ return
+ }
+ x.NetworkIds = &NetworkIdentifiers{}
+ x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1487,6 +1605,41 @@ func (x *ApplicationDownlink) MarshalProtoJSON(s *jsonplugin.MarshalState) {
// NOTE: ApplicationDownlink_ConfirmedRetry does not seem to implement MarshalProtoJSON.
golang.MarshalMessage(s, x.ConfirmedRetry)
}
+ if x.Locations != nil || s.HasField("locations") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("locations")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Locations {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ v.MarshalProtoJSON(s.WithField("locations"))
+ }
+ s.WriteObjectEnd()
+ }
+ if x.VersionIds != nil || s.HasField("version_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("version_ids")
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON.
+ golang.MarshalMessage(s, x.VersionIds)
+ }
+ if x.NetworkIds != nil || s.HasField("network_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("network_ids")
+ x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
+ }
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -1564,6 +1717,45 @@ func (x *ApplicationDownlink) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) {
var v ApplicationDownlink_ConfirmedRetry
golang.UnmarshalMessage(s, &v)
x.ConfirmedRetry = &v
+ case "locations":
+ s.AddField("locations")
+ if s.ReadNil() {
+ x.Locations = nil
+ return
+ }
+ x.Locations = make(map[string]*Location)
+ s.ReadStringMap(func(key string) {
+ var v Location
+ v.UnmarshalProtoJSON(s)
+ x.Locations[key] = &v
+ })
+ case "version_ids", "versionIds":
+ s.AddField("version_ids")
+ if s.ReadNil() {
+ x.VersionIds = nil
+ return
+ }
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON.
+ var v EndDeviceVersionIdentifiers
+ golang.UnmarshalMessage(s, &v)
+ x.VersionIds = &v
+ case "network_ids", "networkIds":
+ if s.ReadNil() {
+ x.NetworkIds = nil
+ return
+ }
+ x.NetworkIds = &NetworkIdentifiers{}
+ x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1655,6 +1847,41 @@ func (x *ApplicationDownlinkFailed) MarshalProtoJSON(s *jsonplugin.MarshalState)
// NOTE: ErrorDetails does not seem to implement MarshalProtoJSON.
golang.MarshalMessage(s, x.Error)
}
+ if x.Locations != nil || s.HasField("locations") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("locations")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Locations {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ v.MarshalProtoJSON(s.WithField("locations"))
+ }
+ s.WriteObjectEnd()
+ }
+ if x.VersionIds != nil || s.HasField("version_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("version_ids")
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON.
+ golang.MarshalMessage(s, x.VersionIds)
+ }
+ if x.NetworkIds != nil || s.HasField("network_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("network_ids")
+ x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
+ }
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -1689,6 +1916,45 @@ func (x *ApplicationDownlinkFailed) UnmarshalProtoJSON(s *jsonplugin.UnmarshalSt
var v ErrorDetails
golang.UnmarshalMessage(s, &v)
x.Error = &v
+ case "locations":
+ s.AddField("locations")
+ if s.ReadNil() {
+ x.Locations = nil
+ return
+ }
+ x.Locations = make(map[string]*Location)
+ s.ReadStringMap(func(key string) {
+ var v Location
+ v.UnmarshalProtoJSON(s)
+ x.Locations[key] = &v
+ })
+ case "version_ids", "versionIds":
+ s.AddField("version_ids")
+ if s.ReadNil() {
+ x.VersionIds = nil
+ return
+ }
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON.
+ var v EndDeviceVersionIdentifiers
+ golang.UnmarshalMessage(s, &v)
+ x.VersionIds = &v
+ case "network_ids", "networkIds":
+ if s.ReadNil() {
+ x.NetworkIds = nil
+ return
+ }
+ x.NetworkIds = &NetworkIdentifiers{}
+ x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1727,6 +1993,41 @@ func (x *ApplicationInvalidatedDownlinks) MarshalProtoJSON(s *jsonplugin.Marshal
s.WriteObjectField("session_key_id")
s.WriteBytes(x.SessionKeyId)
}
+ if x.Locations != nil || s.HasField("locations") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("locations")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Locations {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ v.MarshalProtoJSON(s.WithField("locations"))
+ }
+ s.WriteObjectEnd()
+ }
+ if x.VersionIds != nil || s.HasField("version_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("version_ids")
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON.
+ golang.MarshalMessage(s, x.VersionIds)
+ }
+ if x.NetworkIds != nil || s.HasField("network_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("network_ids")
+ x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
+ }
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
s.WriteObjectEnd()
}
@@ -1768,6 +2069,45 @@ func (x *ApplicationInvalidatedDownlinks) UnmarshalProtoJSON(s *jsonplugin.Unmar
case "session_key_id", "sessionKeyId":
s.AddField("session_key_id")
x.SessionKeyId = s.ReadBytes()
+ case "locations":
+ s.AddField("locations")
+ if s.ReadNil() {
+ x.Locations = nil
+ return
+ }
+ x.Locations = make(map[string]*Location)
+ s.ReadStringMap(func(key string) {
+ var v Location
+ v.UnmarshalProtoJSON(s)
+ x.Locations[key] = &v
+ })
+ case "version_ids", "versionIds":
+ s.AddField("version_ids")
+ if s.ReadNil() {
+ x.VersionIds = nil
+ return
+ }
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON.
+ var v EndDeviceVersionIdentifiers
+ golang.UnmarshalMessage(s, &v)
+ x.VersionIds = &v
+ case "network_ids", "networkIds":
+ if s.ReadNil() {
+ x.NetworkIds = nil
+ return
+ }
+ x.NetworkIds = &NetworkIdentifiers{}
+ x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
}
})
}
@@ -1859,6 +2199,142 @@ func (x *DownlinkQueueOperationErrorDetails) UnmarshalJSON(b []byte) error {
return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x)
}
+// MarshalProtoJSON marshals the ApplicationServiceData message to JSON.
+func (x *ApplicationServiceData) MarshalProtoJSON(s *jsonplugin.MarshalState) {
+ if x == nil {
+ s.WriteNil()
+ return
+ }
+ s.WriteObjectStart()
+ var wroteField bool
+ if x.Service != "" || s.HasField("service") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("service")
+ s.WriteString(x.Service)
+ }
+ if x.Data != nil || s.HasField("data") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("data")
+ if x.Data == nil {
+ s.WriteNil()
+ } else {
+ golang.MarshalStruct(s, x.Data)
+ }
+ }
+ if x.Locations != nil || s.HasField("locations") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("locations")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Locations {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ v.MarshalProtoJSON(s.WithField("locations"))
+ }
+ s.WriteObjectEnd()
+ }
+ if x.VersionIds != nil || s.HasField("version_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("version_ids")
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON.
+ golang.MarshalMessage(s, x.VersionIds)
+ }
+ if x.NetworkIds != nil || s.HasField("network_ids") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("network_ids")
+ x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids"))
+ }
+ if x.Attributes != nil || s.HasField("attributes") {
+ s.WriteMoreIf(&wroteField)
+ s.WriteObjectField("attributes")
+ s.WriteObjectStart()
+ var wroteElement bool
+ for k, v := range x.Attributes {
+ s.WriteMoreIf(&wroteElement)
+ s.WriteObjectStringField(k)
+ s.WriteString(v)
+ }
+ s.WriteObjectEnd()
+ }
+ s.WriteObjectEnd()
+}
+
+// MarshalJSON marshals the ApplicationServiceData to JSON.
+func (x *ApplicationServiceData) MarshalJSON() ([]byte, error) {
+ return jsonplugin.DefaultMarshalerConfig.Marshal(x)
+}
+
+// UnmarshalProtoJSON unmarshals the ApplicationServiceData message from JSON.
+func (x *ApplicationServiceData) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) {
+ if s.ReadNil() {
+ return
+ }
+ s.ReadObject(func(key string) {
+ switch key {
+ default:
+ s.ReadAny() // ignore unknown field
+ case "service":
+ s.AddField("service")
+ x.Service = s.ReadString()
+ case "data":
+ s.AddField("data")
+ if s.ReadNil() {
+ x.Data = nil
+ return
+ }
+ v := golang.UnmarshalStruct(s)
+ if s.Err() != nil {
+ return
+ }
+ x.Data = v
+ case "locations":
+ s.AddField("locations")
+ if s.ReadNil() {
+ x.Locations = nil
+ return
+ }
+ x.Locations = make(map[string]*Location)
+ s.ReadStringMap(func(key string) {
+ var v Location
+ v.UnmarshalProtoJSON(s)
+ x.Locations[key] = &v
+ })
+ case "version_ids", "versionIds":
+ s.AddField("version_ids")
+ if s.ReadNil() {
+ x.VersionIds = nil
+ return
+ }
+ // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON.
+ var v EndDeviceVersionIdentifiers
+ golang.UnmarshalMessage(s, &v)
+ x.VersionIds = &v
+ case "network_ids", "networkIds":
+ if s.ReadNil() {
+ x.NetworkIds = nil
+ return
+ }
+ x.NetworkIds = &NetworkIdentifiers{}
+ x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true))
+ case "attributes":
+ s.AddField("attributes")
+ if s.ReadNil() {
+ x.Attributes = nil
+ return
+ }
+ x.Attributes = make(map[string]string)
+ s.ReadStringMap(func(key string) {
+ x.Attributes[key] = s.ReadString()
+ })
+ }
+ })
+}
+
+// UnmarshalJSON unmarshals the ApplicationServiceData from JSON.
+func (x *ApplicationServiceData) UnmarshalJSON(b []byte) error {
+ return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x)
+}
+
// MarshalProtoJSON marshals the ApplicationUp message to JSON.
func (x *ApplicationUp) MarshalProtoJSON(s *jsonplugin.MarshalState) {
if x == nil {
@@ -1931,8 +2407,7 @@ func (x *ApplicationUp) MarshalProtoJSON(s *jsonplugin.MarshalState) {
case *ApplicationUp_ServiceData:
s.WriteMoreIf(&wroteField)
s.WriteObjectField("service_data")
- // NOTE: ApplicationServiceData does not seem to implement MarshalProtoJSON.
- golang.MarshalMessage(s, ov.ServiceData)
+ ov.ServiceData.MarshalProtoJSON(s.WithField("service_data"))
}
}
if x.Simulated || s.HasField("simulated") {
@@ -2073,17 +2548,14 @@ func (x *ApplicationUp) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) {
ov.LocationSolved = &ApplicationLocation{}
ov.LocationSolved.UnmarshalProtoJSON(s.WithField("location_solved", true))
case "service_data", "serviceData":
- s.AddField("service_data")
ov := &ApplicationUp_ServiceData{}
x.Up = ov
if s.ReadNil() {
ov.ServiceData = nil
return
}
- // NOTE: ApplicationServiceData does not seem to implement UnmarshalProtoJSON.
- var v ApplicationServiceData
- golang.UnmarshalMessage(s, &v)
- ov.ServiceData = &v
+ ov.ServiceData = &ApplicationServiceData{}
+ ov.ServiceData.UnmarshalProtoJSON(s.WithField("service_data", true))
case "simulated":
s.AddField("simulated")
x.Simulated = s.ReadBool()
diff --git a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go
index 0c6cc9e100..f921d78b07 100644
--- a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go
+++ b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go
@@ -407,6 +407,7 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{
"end_device.mac_state.last_network_initiated_downlink_at",
"end_device.mac_state.lorawan_version",
"end_device.mac_state.pending_application_downlink",
+ "end_device.mac_state.pending_application_downlink.attributes",
"end_device.mac_state.pending_application_downlink.class_b_c",
"end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -420,8 +421,22 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{
"end_device.mac_state.pending_application_downlink.f_cnt",
"end_device.mac_state.pending_application_downlink.f_port",
"end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device.mac_state.pending_application_downlink.locations",
+ "end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.mac_state.pending_application_downlink.priority",
"end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device.mac_state.pending_join_request",
"end_device.mac_state.pending_join_request.cf_list",
"end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -623,6 +638,7 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{
"end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device.pending_mac_state.lorawan_version",
"end_device.pending_mac_state.pending_application_downlink",
+ "end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -636,8 +652,22 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{
"end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device.pending_mac_state.pending_application_downlink.priority",
"end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device.pending_mac_state.pending_join_request",
"end_device.pending_mac_state.pending_join_request.cf_list",
"end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
@@ -1195,6 +1225,7 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{
"end_device_template.end_device.mac_state.last_network_initiated_downlink_at",
"end_device_template.end_device.mac_state.lorawan_version",
"end_device_template.end_device.mac_state.pending_application_downlink",
+ "end_device_template.end_device.mac_state.pending_application_downlink.attributes",
"end_device_template.end_device.mac_state.pending_application_downlink.class_b_c",
"end_device_template.end_device.mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device_template.end_device.mac_state.pending_application_downlink.class_b_c.gateways",
@@ -1208,8 +1239,22 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{
"end_device_template.end_device.mac_state.pending_application_downlink.f_cnt",
"end_device_template.end_device.mac_state.pending_application_downlink.f_port",
"end_device_template.end_device.mac_state.pending_application_downlink.frm_payload",
+ "end_device_template.end_device.mac_state.pending_application_downlink.locations",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device_template.end_device.mac_state.pending_application_downlink.priority",
"end_device_template.end_device.mac_state.pending_application_downlink.session_key_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.model_id",
"end_device_template.end_device.mac_state.pending_join_request",
"end_device_template.end_device.mac_state.pending_join_request.cf_list",
"end_device_template.end_device.mac_state.pending_join_request.cf_list.ch_masks",
@@ -1411,6 +1456,7 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{
"end_device_template.end_device.pending_mac_state.last_network_initiated_downlink_at",
"end_device_template.end_device.pending_mac_state.lorawan_version",
"end_device_template.end_device.pending_mac_state.pending_application_downlink",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.attributes",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways",
@@ -1424,8 +1470,22 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{
"end_device_template.end_device.pending_mac_state.pending_application_downlink.f_cnt",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.f_port",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.frm_payload",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.locations",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.net_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.priority",
"end_device_template.end_device.pending_mac_state.pending_application_downlink.session_key_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.band_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version",
+ "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.model_id",
"end_device_template.end_device.pending_mac_state.pending_join_request",
"end_device_template.end_device.pending_mac_state.pending_join_request.cf_list",
"end_device_template.end_device.pending_mac_state.pending_join_request.cf_list.ch_masks",
diff --git a/pkg/webui/locales/ja.json b/pkg/webui/locales/ja.json
index 512ee5a683..efe3f93b0a 100644
--- a/pkg/webui/locales/ja.json
+++ b/pkg/webui/locales/ja.json
@@ -2143,7 +2143,7 @@
"error:pkg/applicationserver/io/web:validate_body": "本文を検証する",
"error:pkg/applicationserver/io/web:webhook_not_found": "Webhookが見つかりません",
"error:pkg/applicationserver/io:buffer_full": "バッファがいっぱいです",
- "error:pkg/applicationserver/metadata/redis:cache_miss": "キャッシュミス",
+ "error:pkg/applicationserver/metadata:field_mask_path_not_supported": "",
"error:pkg/applicationserver/redis:application_uid": "無効なアプリケーションUID `{application_uid}`",
"error:pkg/applicationserver/redis:invalid_fieldmask": "無効なフィールドマスク",
"error:pkg/applicationserver/redis:invalid_identifiers": "無効な識別子",
@@ -2156,7 +2156,6 @@
"error:pkg/applicationserver:field_value": "無効なフィールド `{field}` の値",
"error:pkg/applicationserver:formatter_script_too_large": "フォーマッタースクリプトのサイズが許可された最大サイズを超えています",
"error:pkg/applicationserver:invalid_timeout": "無効なタイムアウト`{timeout}`",
- "error:pkg/applicationserver:invalid_ttl": "無効なTTL `{ttl}`",
"error:pkg/applicationserver:join_server_unavailable": "JoinEUI `{join_eui}` ではジョインサーバが利用できません",
"error:pkg/applicationserver:linking_not_implemented": "リンキングが実装されていません",
"error:pkg/applicationserver:listen_frontend": "アドレス `{address}` でフロントエンドリスナ `{protocol}` を起動失敗",
diff --git a/sdk/js/generated/api-definition.json b/sdk/js/generated/api-definition.json
index 2e234ff95c..4de765ea3b 100644
--- a/sdk/js/generated/api-definition.json
+++ b/sdk/js/generated/api-definition.json
@@ -745,6 +745,7 @@
"simulated",
"up",
"up.downlink_ack",
+ "up.downlink_ack.attributes",
"up.downlink_ack.class_b_c",
"up.downlink_ack.class_b_c.absolute_time",
"up.downlink_ack.class_b_c.gateways",
@@ -758,10 +759,26 @@
"up.downlink_ack.f_cnt",
"up.downlink_ack.f_port",
"up.downlink_ack.frm_payload",
+ "up.downlink_ack.locations",
+ "up.downlink_ack.network_ids",
+ "up.downlink_ack.network_ids.cluster_address",
+ "up.downlink_ack.network_ids.cluster_id",
+ "up.downlink_ack.network_ids.net_id",
+ "up.downlink_ack.network_ids.ns_id",
+ "up.downlink_ack.network_ids.tenant_address",
+ "up.downlink_ack.network_ids.tenant_id",
"up.downlink_ack.priority",
"up.downlink_ack.session_key_id",
+ "up.downlink_ack.version_ids",
+ "up.downlink_ack.version_ids.band_id",
+ "up.downlink_ack.version_ids.brand_id",
+ "up.downlink_ack.version_ids.firmware_version",
+ "up.downlink_ack.version_ids.hardware_version",
+ "up.downlink_ack.version_ids.model_id",
"up.downlink_failed",
+ "up.downlink_failed.attributes",
"up.downlink_failed.downlink",
+ "up.downlink_failed.downlink.attributes",
"up.downlink_failed.downlink.class_b_c",
"up.downlink_failed.downlink.class_b_c.absolute_time",
"up.downlink_failed.downlink.class_b_c.gateways",
@@ -775,8 +792,22 @@
"up.downlink_failed.downlink.f_cnt",
"up.downlink_failed.downlink.f_port",
"up.downlink_failed.downlink.frm_payload",
+ "up.downlink_failed.downlink.locations",
+ "up.downlink_failed.downlink.network_ids",
+ "up.downlink_failed.downlink.network_ids.cluster_address",
+ "up.downlink_failed.downlink.network_ids.cluster_id",
+ "up.downlink_failed.downlink.network_ids.net_id",
+ "up.downlink_failed.downlink.network_ids.ns_id",
+ "up.downlink_failed.downlink.network_ids.tenant_address",
+ "up.downlink_failed.downlink.network_ids.tenant_id",
"up.downlink_failed.downlink.priority",
"up.downlink_failed.downlink.session_key_id",
+ "up.downlink_failed.downlink.version_ids",
+ "up.downlink_failed.downlink.version_ids.band_id",
+ "up.downlink_failed.downlink.version_ids.brand_id",
+ "up.downlink_failed.downlink.version_ids.firmware_version",
+ "up.downlink_failed.downlink.version_ids.hardware_version",
+ "up.downlink_failed.downlink.version_ids.model_id",
"up.downlink_failed.error",
"up.downlink_failed.error.attributes",
"up.downlink_failed.error.cause",
@@ -791,7 +822,22 @@
"up.downlink_failed.error.message_format",
"up.downlink_failed.error.name",
"up.downlink_failed.error.namespace",
+ "up.downlink_failed.locations",
+ "up.downlink_failed.network_ids",
+ "up.downlink_failed.network_ids.cluster_address",
+ "up.downlink_failed.network_ids.cluster_id",
+ "up.downlink_failed.network_ids.net_id",
+ "up.downlink_failed.network_ids.ns_id",
+ "up.downlink_failed.network_ids.tenant_address",
+ "up.downlink_failed.network_ids.tenant_id",
+ "up.downlink_failed.version_ids",
+ "up.downlink_failed.version_ids.band_id",
+ "up.downlink_failed.version_ids.brand_id",
+ "up.downlink_failed.version_ids.firmware_version",
+ "up.downlink_failed.version_ids.hardware_version",
+ "up.downlink_failed.version_ids.model_id",
"up.downlink_nack",
+ "up.downlink_nack.attributes",
"up.downlink_nack.class_b_c",
"up.downlink_nack.class_b_c.absolute_time",
"up.downlink_nack.class_b_c.gateways",
@@ -805,13 +851,43 @@
"up.downlink_nack.f_cnt",
"up.downlink_nack.f_port",
"up.downlink_nack.frm_payload",
+ "up.downlink_nack.locations",
+ "up.downlink_nack.network_ids",
+ "up.downlink_nack.network_ids.cluster_address",
+ "up.downlink_nack.network_ids.cluster_id",
+ "up.downlink_nack.network_ids.net_id",
+ "up.downlink_nack.network_ids.ns_id",
+ "up.downlink_nack.network_ids.tenant_address",
+ "up.downlink_nack.network_ids.tenant_id",
"up.downlink_nack.priority",
"up.downlink_nack.session_key_id",
+ "up.downlink_nack.version_ids",
+ "up.downlink_nack.version_ids.band_id",
+ "up.downlink_nack.version_ids.brand_id",
+ "up.downlink_nack.version_ids.firmware_version",
+ "up.downlink_nack.version_ids.hardware_version",
+ "up.downlink_nack.version_ids.model_id",
"up.downlink_queue_invalidated",
+ "up.downlink_queue_invalidated.attributes",
"up.downlink_queue_invalidated.downlinks",
"up.downlink_queue_invalidated.last_f_cnt_down",
+ "up.downlink_queue_invalidated.locations",
+ "up.downlink_queue_invalidated.network_ids",
+ "up.downlink_queue_invalidated.network_ids.cluster_address",
+ "up.downlink_queue_invalidated.network_ids.cluster_id",
+ "up.downlink_queue_invalidated.network_ids.net_id",
+ "up.downlink_queue_invalidated.network_ids.ns_id",
+ "up.downlink_queue_invalidated.network_ids.tenant_address",
+ "up.downlink_queue_invalidated.network_ids.tenant_id",
"up.downlink_queue_invalidated.session_key_id",
+ "up.downlink_queue_invalidated.version_ids",
+ "up.downlink_queue_invalidated.version_ids.band_id",
+ "up.downlink_queue_invalidated.version_ids.brand_id",
+ "up.downlink_queue_invalidated.version_ids.firmware_version",
+ "up.downlink_queue_invalidated.version_ids.hardware_version",
+ "up.downlink_queue_invalidated.version_ids.model_id",
"up.downlink_queued",
+ "up.downlink_queued.attributes",
"up.downlink_queued.class_b_c",
"up.downlink_queued.class_b_c.absolute_time",
"up.downlink_queued.class_b_c.gateways",
@@ -825,9 +901,24 @@
"up.downlink_queued.f_cnt",
"up.downlink_queued.f_port",
"up.downlink_queued.frm_payload",
+ "up.downlink_queued.locations",
+ "up.downlink_queued.network_ids",
+ "up.downlink_queued.network_ids.cluster_address",
+ "up.downlink_queued.network_ids.cluster_id",
+ "up.downlink_queued.network_ids.net_id",
+ "up.downlink_queued.network_ids.ns_id",
+ "up.downlink_queued.network_ids.tenant_address",
+ "up.downlink_queued.network_ids.tenant_id",
"up.downlink_queued.priority",
"up.downlink_queued.session_key_id",
+ "up.downlink_queued.version_ids",
+ "up.downlink_queued.version_ids.band_id",
+ "up.downlink_queued.version_ids.brand_id",
+ "up.downlink_queued.version_ids.firmware_version",
+ "up.downlink_queued.version_ids.hardware_version",
+ "up.downlink_queued.version_ids.model_id",
"up.downlink_sent",
+ "up.downlink_sent.attributes",
"up.downlink_sent.class_b_c",
"up.downlink_sent.class_b_c.absolute_time",
"up.downlink_sent.class_b_c.gateways",
@@ -841,17 +932,46 @@
"up.downlink_sent.f_cnt",
"up.downlink_sent.f_port",
"up.downlink_sent.frm_payload",
+ "up.downlink_sent.locations",
+ "up.downlink_sent.network_ids",
+ "up.downlink_sent.network_ids.cluster_address",
+ "up.downlink_sent.network_ids.cluster_id",
+ "up.downlink_sent.network_ids.net_id",
+ "up.downlink_sent.network_ids.ns_id",
+ "up.downlink_sent.network_ids.tenant_address",
+ "up.downlink_sent.network_ids.tenant_id",
"up.downlink_sent.priority",
"up.downlink_sent.session_key_id",
+ "up.downlink_sent.version_ids",
+ "up.downlink_sent.version_ids.band_id",
+ "up.downlink_sent.version_ids.brand_id",
+ "up.downlink_sent.version_ids.firmware_version",
+ "up.downlink_sent.version_ids.hardware_version",
+ "up.downlink_sent.version_ids.model_id",
"up.join_accept",
"up.join_accept.app_s_key",
"up.join_accept.app_s_key.encrypted_key",
"up.join_accept.app_s_key.kek_label",
"up.join_accept.app_s_key.key",
+ "up.join_accept.attributes",
"up.join_accept.invalidated_downlinks",
+ "up.join_accept.locations",
+ "up.join_accept.network_ids",
+ "up.join_accept.network_ids.cluster_address",
+ "up.join_accept.network_ids.cluster_id",
+ "up.join_accept.network_ids.net_id",
+ "up.join_accept.network_ids.ns_id",
+ "up.join_accept.network_ids.tenant_address",
+ "up.join_accept.network_ids.tenant_id",
"up.join_accept.pending_session",
"up.join_accept.received_at",
"up.join_accept.session_key_id",
+ "up.join_accept.version_ids",
+ "up.join_accept.version_ids.band_id",
+ "up.join_accept.version_ids.brand_id",
+ "up.join_accept.version_ids.firmware_version",
+ "up.join_accept.version_ids.hardware_version",
+ "up.join_accept.version_ids.model_id",
"up.location_solved",
"up.location_solved.attributes",
"up.location_solved.location",
@@ -862,13 +982,29 @@
"up.location_solved.location.source",
"up.location_solved.service",
"up.service_data",
+ "up.service_data.attributes",
"up.service_data.data",
+ "up.service_data.locations",
+ "up.service_data.network_ids",
+ "up.service_data.network_ids.cluster_address",
+ "up.service_data.network_ids.cluster_id",
+ "up.service_data.network_ids.net_id",
+ "up.service_data.network_ids.ns_id",
+ "up.service_data.network_ids.tenant_address",
+ "up.service_data.network_ids.tenant_id",
"up.service_data.service",
+ "up.service_data.version_ids",
+ "up.service_data.version_ids.band_id",
+ "up.service_data.version_ids.brand_id",
+ "up.service_data.version_ids.firmware_version",
+ "up.service_data.version_ids.hardware_version",
+ "up.service_data.version_ids.model_id",
"up.uplink_message",
"up.uplink_message.app_s_key",
"up.uplink_message.app_s_key.encrypted_key",
"up.uplink_message.app_s_key.kek_label",
"up.uplink_message.app_s_key.key",
+ "up.uplink_message.attributes",
"up.uplink_message.confirmed",
"up.uplink_message.consumed_airtime",
"up.uplink_message.decoded_payload",
@@ -924,6 +1060,7 @@
"up.uplink_message.version_ids.hardware_version",
"up.uplink_message.version_ids.model_id",
"up.uplink_normalized",
+ "up.uplink_normalized.attributes",
"up.uplink_normalized.confirmed",
"up.uplink_normalized.consumed_airtime",
"up.uplink_normalized.f_cnt",
@@ -4754,6 +4891,7 @@
"mac_state.last_network_initiated_downlink_at",
"mac_state.lorawan_version",
"mac_state.pending_application_downlink",
+ "mac_state.pending_application_downlink.attributes",
"mac_state.pending_application_downlink.class_b_c",
"mac_state.pending_application_downlink.class_b_c.absolute_time",
"mac_state.pending_application_downlink.class_b_c.gateways",
@@ -4762,8 +4900,22 @@
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.locations",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
+ "mac_state.pending_application_downlink.version_ids",
+ "mac_state.pending_application_downlink.version_ids.band_id",
+ "mac_state.pending_application_downlink.version_ids.brand_id",
+ "mac_state.pending_application_downlink.version_ids.firmware_version",
+ "mac_state.pending_application_downlink.version_ids.hardware_version",
+ "mac_state.pending_application_downlink.version_ids.model_id",
"mac_state.pending_relay_downlink",
"mac_state.pending_relay_downlink.raw_payload",
"mac_state.pending_requests",
@@ -5370,6 +5522,13 @@
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
"mac_state.pending_relay_downlink",
@@ -5966,6 +6125,7 @@
"mac_state.last_network_initiated_downlink_at",
"mac_state.lorawan_version",
"mac_state.pending_application_downlink",
+ "mac_state.pending_application_downlink.attributes",
"mac_state.pending_application_downlink.class_b_c",
"mac_state.pending_application_downlink.class_b_c.absolute_time",
"mac_state.pending_application_downlink.class_b_c.gateways",
@@ -5974,8 +6134,22 @@
"mac_state.pending_application_downlink.f_cnt",
"mac_state.pending_application_downlink.f_port",
"mac_state.pending_application_downlink.frm_payload",
+ "mac_state.pending_application_downlink.locations",
+ "mac_state.pending_application_downlink.network_ids",
+ "mac_state.pending_application_downlink.network_ids.cluster_address",
+ "mac_state.pending_application_downlink.network_ids.cluster_id",
+ "mac_state.pending_application_downlink.network_ids.net_id",
+ "mac_state.pending_application_downlink.network_ids.ns_id",
+ "mac_state.pending_application_downlink.network_ids.tenant_address",
+ "mac_state.pending_application_downlink.network_ids.tenant_id",
"mac_state.pending_application_downlink.priority",
"mac_state.pending_application_downlink.session_key_id",
+ "mac_state.pending_application_downlink.version_ids",
+ "mac_state.pending_application_downlink.version_ids.band_id",
+ "mac_state.pending_application_downlink.version_ids.brand_id",
+ "mac_state.pending_application_downlink.version_ids.firmware_version",
+ "mac_state.pending_application_downlink.version_ids.hardware_version",
+ "mac_state.pending_application_downlink.version_ids.model_id",
"mac_state.pending_relay_downlink",
"mac_state.pending_relay_downlink.raw_payload",
"mac_state.pending_requests",
diff --git a/sdk/js/generated/api.json b/sdk/js/generated/api.json
index f953f176c2..5c4c2aae19 100644
--- a/sdk/js/generated/api.json
+++ b/sdk/js/generated/api.json
@@ -38661,6 +38661,110 @@
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
+ },
+ {
+ "name": "locations",
+ "description": "End device location metadata, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "LocationsEntry",
+ "longType": "ApplicationDownlink.LocationsEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlink.LocationsEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "version_ids",
+ "description": "End device version identifiers, set by the Application Server while handling the message.",
+ "label": "",
+ "type": "EndDeviceVersionIdentifiers",
+ "longType": "EndDeviceVersionIdentifiers",
+ "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "network_ids",
+ "description": "Network identifiers, set by the Network Server that handles the message.",
+ "label": "",
+ "type": "NetworkIdentifiers",
+ "longType": "NetworkIdentifiers",
+ "fullType": "ttn.lorawan.v3.NetworkIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationDownlink.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlink.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationDownlink.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationDownlink.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
}
]
},
@@ -38748,6 +38852,42 @@
}
]
},
+ {
+ "name": "LocationsEntry",
+ "longName": "ApplicationDownlink.LocationsEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationDownlink.LocationsEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
{
"name": "ApplicationDownlinkFailed",
"longName": "ApplicationDownlinkFailed",
@@ -38797,83 +38937,71 @@
}
]
}
- }
- ]
- },
- {
- "name": "ApplicationDownlinks",
- "longName": "ApplicationDownlinks",
- "fullName": "ttn.lorawan.v3.ApplicationDownlinks",
- "description": "",
- "hasExtensions": false,
- "hasFields": true,
- "hasOneofs": false,
- "extensions": [],
- "fields": [
+ },
{
- "name": "downlinks",
- "description": "",
+ "name": "locations",
+ "description": "End device location metadata, set by the Application Server while handling the message.",
"label": "repeated",
- "type": "ApplicationDownlink",
- "longType": "ApplicationDownlink",
- "fullType": "ttn.lorawan.v3.ApplicationDownlink",
- "ismap": false,
+ "type": "LocationsEntry",
+ "longType": "ApplicationDownlinkFailed.LocationsEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry",
+ "ismap": true,
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
- }
- ]
- },
- {
- "name": "ApplicationInvalidatedDownlinks",
- "longName": "ApplicationInvalidatedDownlinks",
- "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks",
- "description": "",
- "hasExtensions": false,
- "hasFields": true,
- "hasOneofs": false,
- "extensions": [],
- "fields": [
+ },
{
- "name": "downlinks",
- "description": "",
- "label": "repeated",
- "type": "ApplicationDownlink",
- "longType": "ApplicationDownlink",
- "fullType": "ttn.lorawan.v3.ApplicationDownlink",
+ "name": "version_ids",
+ "description": "End device version identifiers, set by the Application Server while handling the message.",
+ "label": "",
+ "type": "EndDeviceVersionIdentifiers",
+ "longType": "EndDeviceVersionIdentifiers",
+ "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
},
{
- "name": "last_f_cnt_down",
- "description": "",
+ "name": "network_ids",
+ "description": "Network identifiers, set by the Network Server that handles the message.",
"label": "",
- "type": "uint32",
- "longType": "uint32",
- "fullType": "uint32",
+ "type": "NetworkIdentifiers",
+ "longType": "NetworkIdentifiers",
+ "fullType": "ttn.lorawan.v3.NetworkIdentifiers",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
},
{
- "name": "session_key_id",
- "description": "",
- "label": "",
- "type": "bytes",
- "longType": "bytes",
- "fullType": "bytes",
- "ismap": false,
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationDownlinkFailed.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry",
+ "ismap": true,
"isoneof": false,
"oneofdecl": "",
"defaultValue": "",
"options": {
"validate.rules": [
{
- "name": "bytes.max_len",
- "value": 2048
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
}
]
}
@@ -38881,9 +39009,9 @@
]
},
{
- "name": "ApplicationJoinAccept",
- "longName": "ApplicationJoinAccept",
- "fullName": "ttn.lorawan.v3.ApplicationJoinAccept",
+ "name": "AttributesEntry",
+ "longName": "ApplicationDownlinkFailed.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry",
"description": "",
"hasExtensions": false,
"hasFields": true,
@@ -38891,87 +39019,631 @@
"extensions": [],
"fields": [
{
- "name": "session_key_id",
- "description": "Join Server issued identifier for the session keys negotiated in this join.",
+ "name": "key",
+ "description": "",
"label": "",
- "type": "bytes",
- "longType": "bytes",
- "fullType": "bytes",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
- "defaultValue": "",
- "options": {
- "validate.rules": [
- {
- "name": "bytes.max_len",
- "value": 2048
- }
- ]
- }
+ "defaultValue": ""
},
{
- "name": "app_s_key",
- "description": "Encrypted Application Session Key (if Join Server sent it to Network Server).",
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "LocationsEntry",
+ "longName": "ApplicationDownlinkFailed.LocationsEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "ApplicationDownlinks",
+ "longName": "ApplicationDownlinks",
+ "fullName": "ttn.lorawan.v3.ApplicationDownlinks",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "downlinks",
+ "description": "",
+ "label": "repeated",
+ "type": "ApplicationDownlink",
+ "longType": "ApplicationDownlink",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlink",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "ApplicationInvalidatedDownlinks",
+ "longName": "ApplicationInvalidatedDownlinks",
+ "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "downlinks",
+ "description": "",
+ "label": "repeated",
+ "type": "ApplicationDownlink",
+ "longType": "ApplicationDownlink",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlink",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "last_f_cnt_down",
+ "description": "",
+ "label": "",
+ "type": "uint32",
+ "longType": "uint32",
+ "fullType": "uint32",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "session_key_id",
+ "description": "",
+ "label": "",
+ "type": "bytes",
+ "longType": "bytes",
+ "fullType": "bytes",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "bytes.max_len",
+ "value": 2048
+ }
+ ]
+ }
+ },
+ {
+ "name": "locations",
+ "description": "End device location metadata, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "LocationsEntry",
+ "longType": "ApplicationInvalidatedDownlinks.LocationsEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "version_ids",
+ "description": "End device version identifiers, set by the Application Server while handling the message.",
+ "label": "",
+ "type": "EndDeviceVersionIdentifiers",
+ "longType": "EndDeviceVersionIdentifiers",
+ "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "network_ids",
+ "description": "Network identifiers, set by the Network Server that handles the message.",
+ "label": "",
+ "type": "NetworkIdentifiers",
+ "longType": "NetworkIdentifiers",
+ "fullType": "ttn.lorawan.v3.NetworkIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationInvalidatedDownlinks.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationInvalidatedDownlinks.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "LocationsEntry",
+ "longName": "ApplicationInvalidatedDownlinks.LocationsEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "ApplicationJoinAccept",
+ "longName": "ApplicationJoinAccept",
+ "fullName": "ttn.lorawan.v3.ApplicationJoinAccept",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "session_key_id",
+ "description": "Join Server issued identifier for the session keys negotiated in this join.",
+ "label": "",
+ "type": "bytes",
+ "longType": "bytes",
+ "fullType": "bytes",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "bytes.max_len",
+ "value": 2048
+ }
+ ]
+ }
+ },
+ {
+ "name": "app_s_key",
+ "description": "Encrypted Application Session Key (if Join Server sent it to Network Server).",
+ "label": "",
+ "type": "KeyEnvelope",
+ "longType": "KeyEnvelope",
+ "fullType": "ttn.lorawan.v3.KeyEnvelope",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "invalidated_downlinks",
+ "description": "Downlink messages in the queue that got invalidated because of the session change.",
+ "label": "repeated",
+ "type": "ApplicationDownlink",
+ "longType": "ApplicationDownlink",
+ "fullType": "ttn.lorawan.v3.ApplicationDownlink",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "pending_session",
+ "description": "Indicates whether the security context refers to the pending session, i.e. when this join-accept is an answer to a\nrejoin-request.",
+ "label": "",
+ "type": "bool",
+ "longType": "bool",
+ "fullType": "bool",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "received_at",
+ "description": "Server time when the Network Server received the message.",
+ "label": "",
+ "type": "Timestamp",
+ "longType": "google.protobuf.Timestamp",
+ "fullType": "google.protobuf.Timestamp",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "timestamp.required",
+ "value": true
+ }
+ ]
+ }
+ },
+ {
+ "name": "locations",
+ "description": "End device location metadata, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "LocationsEntry",
+ "longType": "ApplicationJoinAccept.LocationsEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "version_ids",
+ "description": "End device version identifiers, set by the Application Server while handling the message.",
+ "label": "",
+ "type": "EndDeviceVersionIdentifiers",
+ "longType": "EndDeviceVersionIdentifiers",
+ "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "network_ids",
+ "description": "Network identifiers, set by the Network Server that handles the message.",
+ "label": "",
+ "type": "NetworkIdentifiers",
+ "longType": "NetworkIdentifiers",
+ "fullType": "ttn.lorawan.v3.NetworkIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationJoinAccept.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationJoinAccept.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "LocationsEntry",
+ "longName": "ApplicationJoinAccept.LocationsEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "name": "ApplicationLocation",
+ "longName": "ApplicationLocation",
+ "fullName": "ttn.lorawan.v3.ApplicationLocation",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "service",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "location",
+ "description": "",
+ "label": "",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "message.required",
+ "value": true
+ }
+ ]
+ }
+ },
+ {
+ "name": "attributes",
+ "description": "",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationLocation.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationLocation.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
"label": "",
- "type": "KeyEnvelope",
- "longType": "KeyEnvelope",
- "fullType": "ttn.lorawan.v3.KeyEnvelope",
- "ismap": false,
- "isoneof": false,
- "oneofdecl": "",
- "defaultValue": ""
- },
- {
- "name": "invalidated_downlinks",
- "description": "Downlink messages in the queue that got invalidated because of the session change.",
- "label": "repeated",
- "type": "ApplicationDownlink",
- "longType": "ApplicationDownlink",
- "fullType": "ttn.lorawan.v3.ApplicationDownlink",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
},
{
- "name": "pending_session",
- "description": "Indicates whether the security context refers to the pending session, i.e. when this join-accept is an answer to a\nrejoin-request.",
+ "name": "value",
+ "description": "",
"label": "",
- "type": "bool",
- "longType": "bool",
- "fullType": "bool",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
- },
- {
- "name": "received_at",
- "description": "Server time when the Network Server received the message.",
- "label": "",
- "type": "Timestamp",
- "longType": "google.protobuf.Timestamp",
- "fullType": "google.protobuf.Timestamp",
- "ismap": false,
- "isoneof": false,
- "oneofdecl": "",
- "defaultValue": "",
- "options": {
- "validate.rules": [
- {
- "name": "timestamp.required",
- "value": true
- }
- ]
- }
}
]
},
{
- "name": "ApplicationLocation",
- "longName": "ApplicationLocation",
- "fullName": "ttn.lorawan.v3.ApplicationLocation",
+ "name": "ApplicationServiceData",
+ "longName": "ApplicationServiceData",
+ "fullName": "ttn.lorawan.v3.ApplicationServiceData",
"description": "",
"hasExtensions": false,
"hasFields": true,
@@ -38991,32 +39663,60 @@
"defaultValue": ""
},
{
- "name": "location",
+ "name": "data",
"description": "",
"label": "",
- "type": "Location",
- "longType": "Location",
- "fullType": "ttn.lorawan.v3.Location",
+ "type": "Struct",
+ "longType": "google.protobuf.Struct",
+ "fullType": "google.protobuf.Struct",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
- "defaultValue": "",
- "options": {
- "validate.rules": [
- {
- "name": "message.required",
- "value": true
- }
- ]
- }
+ "defaultValue": ""
+ },
+ {
+ "name": "locations",
+ "description": "End device location metadata, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "LocationsEntry",
+ "longType": "ApplicationServiceData.LocationsEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationServiceData.LocationsEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "version_ids",
+ "description": "End device version identifiers, set by the Application Server while handling the message.",
+ "label": "",
+ "type": "EndDeviceVersionIdentifiers",
+ "longType": "EndDeviceVersionIdentifiers",
+ "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "network_ids",
+ "description": "Network identifiers, set by the Network Server that handles the message.",
+ "label": "",
+ "type": "NetworkIdentifiers",
+ "longType": "NetworkIdentifiers",
+ "fullType": "ttn.lorawan.v3.NetworkIdentifiers",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
},
{
"name": "attributes",
- "description": "",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
"label": "repeated",
"type": "AttributesEntry",
- "longType": "ApplicationLocation.AttributesEntry",
- "fullType": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry",
+ "longType": "ApplicationServiceData.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationServiceData.AttributesEntry",
"ismap": true,
"isoneof": false,
"oneofdecl": "",
@@ -39046,8 +39746,8 @@
},
{
"name": "AttributesEntry",
- "longName": "ApplicationLocation.AttributesEntry",
- "fullName": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry",
+ "longName": "ApplicationServiceData.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationServiceData.AttributesEntry",
"description": "",
"hasExtensions": false,
"hasFields": true,
@@ -39081,9 +39781,9 @@
]
},
{
- "name": "ApplicationServiceData",
- "longName": "ApplicationServiceData",
- "fullName": "ttn.lorawan.v3.ApplicationServiceData",
+ "name": "LocationsEntry",
+ "longName": "ApplicationServiceData.LocationsEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationServiceData.LocationsEntry",
"description": "",
"hasExtensions": false,
"hasFields": true,
@@ -39091,7 +39791,7 @@
"extensions": [],
"fields": [
{
- "name": "service",
+ "name": "key",
"description": "",
"label": "",
"type": "string",
@@ -39103,12 +39803,12 @@
"defaultValue": ""
},
{
- "name": "data",
+ "name": "value",
"description": "",
"label": "",
- "type": "Struct",
- "longType": "google.protobuf.Struct",
- "fullType": "google.protobuf.Struct",
+ "type": "Location",
+ "longType": "Location",
+ "fullType": "ttn.lorawan.v3.Location",
"ismap": false,
"isoneof": false,
"oneofdecl": "",
@@ -39603,6 +40303,74 @@
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
+ },
+ {
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationUplink.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationUplink.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationUplink.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationUplink.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
}
]
},
@@ -39869,6 +40637,74 @@
"isoneof": false,
"oneofdecl": "",
"defaultValue": ""
+ },
+ {
+ "name": "attributes",
+ "description": "Attributes for devices, set by the Application Server while handling the message.",
+ "label": "repeated",
+ "type": "AttributesEntry",
+ "longType": "ApplicationUplinkNormalized.AttributesEntry",
+ "fullType": "ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry",
+ "ismap": true,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": "",
+ "options": {
+ "validate.rules": [
+ {
+ "name": "map.max_pairs",
+ "value": 10
+ },
+ {
+ "name": "map.keys.string.max_len",
+ "value": 36
+ },
+ {
+ "name": "map.keys.string.pattern",
+ "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$"
+ },
+ {
+ "name": "map.values.string.max_len",
+ "value": 200
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "AttributesEntry",
+ "longName": "ApplicationUplinkNormalized.AttributesEntry",
+ "fullName": "ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry",
+ "description": "",
+ "hasExtensions": false,
+ "hasFields": true,
+ "hasOneofs": false,
+ "extensions": [],
+ "fields": [
+ {
+ "name": "key",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
+ },
+ {
+ "name": "value",
+ "description": "",
+ "label": "",
+ "type": "string",
+ "longType": "string",
+ "fullType": "string",
+ "ismap": false,
+ "isoneof": false,
+ "oneofdecl": "",
+ "defaultValue": ""
}
]
},
diff --git a/sdk/js/generated/device-entity-map.json b/sdk/js/generated/device-entity-map.json
index 0d65c728ec..62da12da47 100644
--- a/sdk/js/generated/device-entity-map.json
+++ b/sdk/js/generated/device-entity-map.json
@@ -2091,6 +2091,10 @@
"ns",
"ns"
],
+ "attributes": [
+ "ns",
+ "read_only"
+ ],
"class_b_c": {
"_root": [
"ns",
@@ -2125,6 +2129,40 @@
"ns",
"ns"
],
+ "locations": [
+ "ns",
+ "read_only"
+ ],
+ "network_ids": {
+ "_root": [
+ "ns",
+ "ns"
+ ],
+ "cluster_address": [
+ "ns",
+ "ns"
+ ],
+ "cluster_id": [
+ "ns",
+ "ns"
+ ],
+ "net_id": [
+ "ns",
+ "ns"
+ ],
+ "ns_id": [
+ "ns",
+ "ns"
+ ],
+ "tenant_address": [
+ "ns",
+ "ns"
+ ],
+ "tenant_id": [
+ "ns",
+ "ns"
+ ]
+ },
"priority": [
"ns",
"ns"
@@ -2132,7 +2170,33 @@
"session_key_id": [
"ns",
"ns"
- ]
+ ],
+ "version_ids": {
+ "_root": [
+ "ns",
+ "read_only"
+ ],
+ "band_id": [
+ "ns",
+ "read_only"
+ ],
+ "brand_id": [
+ "ns",
+ "read_only"
+ ],
+ "firmware_version": [
+ "ns",
+ "read_only"
+ ],
+ "hardware_version": [
+ "ns",
+ "read_only"
+ ],
+ "model_id": [
+ "ns",
+ "read_only"
+ ]
+ }
},
"pending_relay_downlink": {
"_root": [